xref: /petsc/src/dm/impls/plex/plex.c (revision 34541f0d5412d19a5e7ecf5c94ef1ad5e874e23d)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/vecimpl.h>
4 #include <petsc-private/isimpl.h>
5 
6 /* Logging support */
7 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
8 
9 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
11 
12 #undef __FUNCT__
13 #define __FUNCT__ "VecView_Plex_Local"
14 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
15 {
16   DM             dm;
17   PetscBool      isvtk;
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
22   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
23   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
24   if (isvtk) {
25     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
26     PetscSection            section;
27     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
28 
29     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
30     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
31     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
32     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, NULL);CHKERRQ(ierr);
33     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, NULL);CHKERRQ(ierr);
34     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
35     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
36     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
37     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
38     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
39     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
40       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
41     } else if (cdof && vdof) {
42       SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
43     } else if (cdof) {
44       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
45        * vector or just happens to have the same number of dofs as the dimension. */
46       if (cdof == dim) {
47         ft = PETSC_VTK_CELL_VECTOR_FIELD;
48       } else {
49         ft = PETSC_VTK_CELL_FIELD;
50       }
51     } else if (vdof) {
52       if (vdof == dim) {
53         ft = PETSC_VTK_POINT_VECTOR_FIELD;
54       } else {
55         ft = PETSC_VTK_POINT_FIELD;
56       }
57     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
58 
59     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
60     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
61     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
62   } else {
63     PetscBool isseq;
64 
65     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
66     if (isseq) {
67       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
68     } else {
69       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
70     }
71   }
72   PetscFunctionReturn(0);
73 }
74 
75 #undef __FUNCT__
76 #define __FUNCT__ "VecView_Plex"
77 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
78 {
79   DM             dm;
80   PetscBool      isvtk;
81   PetscErrorCode ierr;
82 
83   PetscFunctionBegin;
84   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
85   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
86   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
87   if (isvtk) {
88     Vec         locv;
89     const char *name;
90 
91     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
92     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
93     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
94     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
95     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
96     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
97     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
98   } else {
99     PetscBool isseq;
100 
101     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
102     if (isseq) {
103       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
104     } else {
105       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
106     }
107   }
108   PetscFunctionReturn(0);
109 }
110 
111 #undef __FUNCT__
112 #define __FUNCT__ "DMPlexView_Ascii"
113 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
114 {
115   DM_Plex          *mesh = (DM_Plex*) dm->data;
116   DM                cdm;
117   DMLabel           markers;
118   PetscSection      coordSection;
119   Vec               coordinates;
120   PetscViewerFormat format;
121   PetscErrorCode    ierr;
122 
123   PetscFunctionBegin;
124   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
125   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
126   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
127   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
128   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
129     const char *name;
130     PetscInt    maxConeSize, maxSupportSize;
131     PetscInt    pStart, pEnd, p;
132     PetscMPIInt rank, size;
133 
134     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
135     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
136     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
137     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
138     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
142     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
143     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
144     for (p = pStart; p < pEnd; ++p) {
145       PetscInt dof, off, s;
146 
147       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
148       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
149       for (s = off; s < off+dof; ++s) {
150         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
151       }
152     }
153     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
154     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
155     for (p = pStart; p < pEnd; ++p) {
156       PetscInt dof, off, c;
157 
158       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
159       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
160       for (c = off; c < off+dof; ++c) {
161         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
162       }
163     }
164     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
165     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
166     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
167     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
168     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors  = 3;
180     PetscReal    scale      = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for (p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for (v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for (e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for (c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscMPIInt size;
282 
283     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
284     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
285     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
286     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
287     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
288     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
289     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
290     if (depth == 1) {
291       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
292       pEnd = pEnd - pStart;
293       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
294       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
295       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
296       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
297       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
298       pEnd = pEnd - pStart;
299       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
300       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
301       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
302       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
303     } else {
304       for (d = 0; d <= dim; d++) {
305         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
306         pEnd = pEnd - pStart;
307         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
308         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
309         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
310         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
311       }
312     }
313     ierr = PetscFree(sizes);CHKERRQ(ierr);
314   }
315   PetscFunctionReturn(0);
316 }
317 
318 #undef __FUNCT__
319 #define __FUNCT__ "DMView_Plex"
320 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
321 {
322   PetscBool      iascii, isbinary;
323   PetscErrorCode ierr;
324 
325   PetscFunctionBegin;
326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
327   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
329   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
330   if (iascii) {
331     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
332 #if 0
333   } else if (isbinary) {
334     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
335 #endif
336   }
337   PetscFunctionReturn(0);
338 }
339 
340 #undef __FUNCT__
341 #define __FUNCT__ "DMDestroy_Plex"
342 PetscErrorCode DMDestroy_Plex(DM dm)
343 {
344   DM_Plex       *mesh = (DM_Plex*) dm->data;
345   DMLabel        next  = mesh->labels;
346   PetscErrorCode ierr;
347 
348   PetscFunctionBegin;
349   if (--mesh->refct > 0) PetscFunctionReturn(0);
350   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
353   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
355   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
356   while (next) {
357     DMLabel tmp = next->next;
358 
359     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
360     next = tmp;
361   }
362   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
364   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
365   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
366   ierr = PetscFree(mesh);CHKERRQ(ierr);
367   PetscFunctionReturn(0);
368 }
369 
370 #undef __FUNCT__
371 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
372 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
373 {
374   const PetscInt *support = NULL;
375   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
376   PetscErrorCode  ierr;
377 
378   PetscFunctionBegin;
379   if (useClosure) {
380     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
381     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
382     for (s = 0; s < supportSize; ++s) {
383       const PetscInt *cone = NULL;
384       PetscInt        coneSize, c, q;
385 
386       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
387       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
388       for (c = 0; c < coneSize; ++c) {
389         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
390           if (cone[c] == adj[q]) break;
391         }
392         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
393       }
394     }
395   } else {
396     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
397     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
398     for (s = 0; s < supportSize; ++s) {
399       const PetscInt *cone = NULL;
400       PetscInt        coneSize, c, q;
401 
402       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
403       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
404       for (c = 0; c < coneSize; ++c) {
405         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
406           if (cone[c] == adj[q]) break;
407         }
408         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
409       }
410     }
411   }
412   *adjSize = numAdj;
413   PetscFunctionReturn(0);
414 }
415 
416 #undef __FUNCT__
417 #define __FUNCT__ "DMPlexGetAdjacency_Private"
418 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
419 {
420   const PetscInt *star  = tmpClosure;
421   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
422   PetscErrorCode  ierr;
423 
424   PetscFunctionBegin;
425   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
426   for (s = 2; s < starSize*2; s += 2) {
427     const PetscInt *closure = NULL;
428     PetscInt        closureSize, c, q;
429 
430     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
431     for (c = 0; c < closureSize*2; c += 2) {
432       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
433         if (closure[c] == adj[q]) break;
434       }
435       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
436     }
437     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
438   }
439   *adjSize = numAdj;
440   PetscFunctionReturn(0);
441 }
442 
443 #undef __FUNCT__
444 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
445 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
446 {
447   DM_Plex *mesh = (DM_Plex*) dm->data;
448 
449   PetscFunctionBegin;
450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
451   mesh->preallocCenterDim = preallocCenterDim;
452   PetscFunctionReturn(0);
453 }
454 
455 #undef __FUNCT__
456 #define __FUNCT__ "DMPlexPreallocateOperator"
457 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
458 {
459   DM_Plex           *mesh = (DM_Plex*) dm->data;
460   MPI_Comm           comm;
461   PetscSF            sf, sfDof, sfAdj;
462   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
463   PetscInt           nleaves, l, p;
464   const PetscInt    *leaves;
465   const PetscSFNode *remotes;
466   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
467   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
468   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
469   PetscLayout        rLayout;
470   PetscInt           locRows, rStart, rEnd, r;
471   PetscMPIInt        size;
472   PetscBool          useClosure, debug = PETSC_FALSE;
473   PetscErrorCode     ierr;
474 
475   PetscFunctionBegin;
476   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
477   ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr);
478   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
479   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
480   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
481   /* Create dof SF based on point SF */
482   if (debug) {
483     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
487     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
488     ierr = PetscSFView(sf, NULL);CHKERRQ(ierr);
489   }
490   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
491   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
492   if (debug) {
493     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
494     ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr);
495   }
496   /* Create section for dof adjacency (dof ==> # adj dof) */
497   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
498   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
499   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
500   if (mesh->preallocCenterDim == dim) {
501     useClosure = PETSC_FALSE;
502   } else if (mesh->preallocCenterDim == 0) {
503     useClosure = PETSC_TRUE;
504   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
505 
506   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
507   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
510   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
511   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
512   /*   Fill in the ghost dofs on the interface */
513   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
514   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
515   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
516 
517   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
518   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
519 
520   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
521 
522   /*
523    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
524     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
525        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
526     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
527        Create sfAdj connecting rootSectionAdj and leafSectionAdj
528     3. Visit unowned points on interface, write adjacencies to adj
529        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
530     4. Visit owned points on interface, write adjacencies to rootAdj
531        Remove redundancy in rootAdj
532    ** The last two traversals use transitive closure
533     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
534        Allocate memory addressed by sectionAdj (cols)
535     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
536    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
537   */
538 
539   for (l = 0; l < nleaves; ++l) {
540     PetscInt dof, off, d, q;
541     PetscInt p = leaves[l], numAdj = maxAdjSize;
542 
543     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
544     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
545     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
546     for (q = 0; q < numAdj; ++q) {
547       PetscInt ndof, ncdof;
548 
549       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
550       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
551       for (d = off; d < off+dof; ++d) {
552         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
553       }
554     }
555   }
556   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
557   if (debug) {
558     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
559     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
560   }
561   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
562   if (size > 1) {
563     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
564     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
565   }
566   if (debug) {
567     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
568     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
569   }
570   /* Add in local adjacency sizes for owned dofs on interface (roots) */
571   for (p = pStart; p < pEnd; ++p) {
572     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
573 
574     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
575     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
576     if (!dof) continue;
577     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
578     if (adof <= 0) continue;
579     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
580     for (q = 0; q < numAdj; ++q) {
581       PetscInt ndof, ncdof;
582 
583       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
584       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
585       for (d = off; d < off+dof; ++d) {
586         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
587       }
588     }
589   }
590   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
591   if (debug) {
592     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
593     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
594   }
595   /* Create adj SF based on dof SF */
596   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
597   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
598   if (debug) {
599     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
600     ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr);
601   }
602   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
603   /* Create leaf adjacency */
604   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
605   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
606   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
607   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
608   for (l = 0; l < nleaves; ++l) {
609     PetscInt dof, off, d, q;
610     PetscInt p = leaves[l], numAdj = maxAdjSize;
611 
612     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
613     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
614     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
615     for (d = off; d < off+dof; ++d) {
616       PetscInt aoff, i = 0;
617 
618       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
619       for (q = 0; q < numAdj; ++q) {
620         PetscInt ndof, ncdof, ngoff, nd;
621 
622         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
623         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
624         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
625         for (nd = 0; nd < ndof-ncdof; ++nd) {
626           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
627           ++i;
628         }
629       }
630     }
631   }
632   /* Debugging */
633   if (debug) {
634     IS tmp;
635     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
636     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
637     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
638   }
639   /* Gather adjacenct indices to root */
640   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
641   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
642   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
643   if (size > 1) {
644     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
645     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
646   }
647   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
648   ierr = PetscFree(adj);CHKERRQ(ierr);
649   /* Debugging */
650   if (debug) {
651     IS tmp;
652     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
653     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
654     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
655   }
656   /* Add in local adjacency indices for owned dofs on interface (roots) */
657   for (p = pStart; p < pEnd; ++p) {
658     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
659 
660     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
661     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
662     if (!dof) continue;
663     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
664     if (adof <= 0) continue;
665     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
666     for (d = off; d < off+dof; ++d) {
667       PetscInt adof, aoff, i;
668 
669       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
670       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
671       i    = adof-1;
672       for (q = 0; q < numAdj; ++q) {
673         PetscInt ndof, ncdof, ngoff, nd;
674 
675         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
676         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
677         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
678         for (nd = 0; nd < ndof-ncdof; ++nd) {
679           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
680           --i;
681         }
682       }
683     }
684   }
685   /* Debugging */
686   if (debug) {
687     IS tmp;
688     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
689     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
690     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
691   }
692   /* Compress indices */
693   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
694   for (p = pStart; p < pEnd; ++p) {
695     PetscInt dof, cdof, off, d;
696     PetscInt adof, aoff;
697 
698     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
699     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
700     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
701     if (!dof) continue;
702     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
703     if (adof <= 0) continue;
704     for (d = off; d < off+dof-cdof; ++d) {
705       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
706       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
707       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
708       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
709     }
710   }
711   /* Debugging */
712   if (debug) {
713     IS tmp;
714     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
715     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
716     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
717     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
718     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
719   }
720   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
721   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
722   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
723   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
724   for (p = pStart; p < pEnd; ++p) {
725     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
726     PetscBool found  = PETSC_TRUE;
727 
728     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
729     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
730     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
731     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
732     for (d = 0; d < dof-cdof; ++d) {
733       PetscInt ldof, rdof;
734 
735       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
736       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
737       if (ldof > 0) {
738         /* We do not own this point */
739       } else if (rdof > 0) {
740         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
741       } else {
742         found = PETSC_FALSE;
743       }
744     }
745     if (found) continue;
746     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
747     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
748     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
749     for (q = 0; q < numAdj; ++q) {
750       PetscInt ndof, ncdof, noff;
751 
752       /* Adjacent points may not be in the section chart */
753       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
754       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
755       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
756       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
757       for (d = goff; d < goff+dof-cdof; ++d) {
758         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
759       }
760     }
761   }
762   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
763   if (debug) {
764     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
765     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
766   }
767   /* Get adjacent indices */
768   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
769   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
770   for (p = pStart; p < pEnd; ++p) {
771     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
772     PetscBool found  = PETSC_TRUE;
773 
774     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
775     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
776     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
777     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
778     for (d = 0; d < dof-cdof; ++d) {
779       PetscInt ldof, rdof;
780 
781       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
782       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
783       if (ldof > 0) {
784         /* We do not own this point */
785       } else if (rdof > 0) {
786         PetscInt aoff, roff;
787 
788         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
789         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
790         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
791       } else {
792         found = PETSC_FALSE;
793       }
794     }
795     if (found) continue;
796     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
797     for (d = goff; d < goff+dof-cdof; ++d) {
798       PetscInt adof, aoff, i = 0;
799 
800       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
801       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
802       for (q = 0; q < numAdj; ++q) {
803         PetscInt        ndof, ncdof, ngoff, nd;
804         const PetscInt *ncind;
805 
806         /* Adjacent points may not be in the section chart */
807         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
808         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
809         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
810         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
811         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
812         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
813           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
814         }
815       }
816       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
817     }
818   }
819   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
820   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
821   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
822   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
823   /* Debugging */
824   if (debug) {
825     IS tmp;
826     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
827     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
828     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
829   }
830   /* Create allocation vectors from adjacency graph */
831   ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr);
832   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr);
833   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
834   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
835   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
836   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
837   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
838   /* Only loop over blocks of rows */
839   if (rStart%bs || rEnd%bs) SETERRQ3(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
840   for (r = rStart/bs; r < rEnd/bs; ++r) {
841     const PetscInt row = r*bs;
842     PetscInt       numCols, cStart, c;
843 
844     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
845     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
846     for (c = cStart; c < cStart+numCols; ++c) {
847       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
848         ++dnz[r-rStart];
849         if (cols[c] >= row) ++dnzu[r-rStart];
850       } else {
851         ++onz[r-rStart];
852         if (cols[c] >= row) ++onzu[r-rStart];
853       }
854     }
855   }
856   if (bs > 1) {
857     for (r = 0; r < locRows/bs; ++r) {
858       dnz[r]  /= bs;
859       onz[r]  /= bs;
860       dnzu[r] /= bs;
861       onzu[r] /= bs;
862     }
863   }
864   /* Set matrix pattern */
865   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
866   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
867   /* Fill matrix with zeros */
868   if (fillMatrix) {
869     PetscScalar *values;
870     PetscInt     maxRowLen = 0;
871 
872     for (r = rStart; r < rEnd; ++r) {
873       PetscInt len;
874 
875       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
876       maxRowLen = PetscMax(maxRowLen, len);
877     }
878     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
879     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
880     for (r = rStart; r < rEnd; ++r) {
881       PetscInt numCols, cStart;
882 
883       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
884       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
885       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
886     }
887     ierr = PetscFree(values);CHKERRQ(ierr);
888     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
889     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
890   }
891   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
892   ierr = PetscFree(cols);CHKERRQ(ierr);
893   PetscFunctionReturn(0);
894 }
895 
896 #if 0
897 #undef __FUNCT__
898 #define __FUNCT__ "DMPlexPreallocateOperator_2"
899 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
900 {
901   PetscInt       *tmpClosure,*tmpAdj,*visits;
902   PetscInt        c,cStart,cEnd,pStart,pEnd;
903   PetscErrorCode  ierr;
904 
905   PetscFunctionBegin;
906   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
907   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
908   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
909 
910   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
911 
912   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
913   npoints = pEnd - pStart;
914 
915   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
916   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
917   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
918   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
919   for (c=cStart; c<cEnd; c++) {
920     PetscInt *support = tmpClosure;
921     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
922     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
923   }
924   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
925   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
926   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
927   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
928 
929   ierr = PetscSFGetRanks();CHKERRQ(ierr);
930 
931 
932   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
933   for (c=cStart; c<cEnd; c++) {
934     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
935     /*
936      Depth-first walk of transitive closure.
937      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
938      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
939      */
940   }
941 
942   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
943   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
944   PetscFunctionReturn(0);
945 }
946 #endif
947 
948 #undef __FUNCT__
949 #define __FUNCT__ "DMCreateMatrix_Plex"
950 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
951 {
952   PetscSection   section, sectionGlobal;
953   PetscInt       bs = -1;
954   PetscInt       localSize;
955   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
956   PetscErrorCode ierr;
957 
958   PetscFunctionBegin;
959 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
960   ierr = MatInitializePackage(NULL);CHKERRQ(ierr);
961 #endif
962   if (!mtype) mtype = MATAIJ;
963   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
964   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
965   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
966   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
967   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
968   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
969   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
970   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
974   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
975   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
976   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
977   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
978   /* Check for symmetric storage */
979   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
980   if (isSymmetric) {
981     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
982   }
983   if (!isShell) {
984     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
985     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
986 
987     if (bs < 0) {
988       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
989         PetscInt pStart, pEnd, p, dof, cdof;
990 
991         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
992         for (p = pStart; p < pEnd; ++p) {
993           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
994           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
995           if (dof-cdof) {
996             if (bs < 0) {
997               bs = dof-cdof;
998             } else if (bs != dof-cdof) {
999               /* Layout does not admit a pointwise block size */
1000               bs = 1;
1001               break;
1002             }
1003           }
1004         }
1005         /* Must have same blocksize on all procs (some might have no points) */
1006         bsLocal = bs;
1007         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1008         bsLocal = bs < 0 ? bsMax : bs;
1009         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1010         if (bsMin != bsMax) {
1011           bs = 1;
1012         } else {
1013           bs = bsMax;
1014         }
1015       } else {
1016         bs = 1;
1017       }
1018     }
1019     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1020     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1021     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1022     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1023     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1024     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1025     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1026   }
1027   PetscFunctionReturn(0);
1028 }
1029 
1030 #undef __FUNCT__
1031 #define __FUNCT__ "DMPlexGetDimension"
1032 /*@
1033   DMPlexGetDimension - Return the topological mesh dimension
1034 
1035   Not collective
1036 
1037   Input Parameter:
1038 . mesh - The DMPlex
1039 
1040   Output Parameter:
1041 . dim - The topological mesh dimension
1042 
1043   Level: beginner
1044 
1045 .seealso: DMPlexCreate()
1046 @*/
1047 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1048 {
1049   DM_Plex *mesh = (DM_Plex*) dm->data;
1050 
1051   PetscFunctionBegin;
1052   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1053   PetscValidPointer(dim, 2);
1054   *dim = mesh->dim;
1055   PetscFunctionReturn(0);
1056 }
1057 
1058 #undef __FUNCT__
1059 #define __FUNCT__ "DMPlexSetDimension"
1060 /*@
1061   DMPlexSetDimension - Set the topological mesh dimension
1062 
1063   Collective on mesh
1064 
1065   Input Parameters:
1066 + mesh - The DMPlex
1067 - dim - The topological mesh dimension
1068 
1069   Level: beginner
1070 
1071 .seealso: DMPlexCreate()
1072 @*/
1073 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1074 {
1075   DM_Plex *mesh = (DM_Plex*) dm->data;
1076 
1077   PetscFunctionBegin;
1078   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1079   PetscValidLogicalCollectiveInt(dm, dim, 2);
1080   mesh->dim               = dim;
1081   mesh->preallocCenterDim = dim;
1082   PetscFunctionReturn(0);
1083 }
1084 
1085 #undef __FUNCT__
1086 #define __FUNCT__ "DMPlexGetChart"
1087 /*@
1088   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1089 
1090   Not collective
1091 
1092   Input Parameter:
1093 . mesh - The DMPlex
1094 
1095   Output Parameters:
1096 + pStart - The first mesh point
1097 - pEnd   - The upper bound for mesh points
1098 
1099   Level: beginner
1100 
1101 .seealso: DMPlexCreate(), DMPlexSetChart()
1102 @*/
1103 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1104 {
1105   DM_Plex       *mesh = (DM_Plex*) dm->data;
1106   PetscErrorCode ierr;
1107 
1108   PetscFunctionBegin;
1109   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1110   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1111   PetscFunctionReturn(0);
1112 }
1113 
1114 #undef __FUNCT__
1115 #define __FUNCT__ "DMPlexSetChart"
1116 /*@
1117   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1118 
1119   Not collective
1120 
1121   Input Parameters:
1122 + mesh - The DMPlex
1123 . pStart - The first mesh point
1124 - pEnd   - The upper bound for mesh points
1125 
1126   Output Parameters:
1127 
1128   Level: beginner
1129 
1130 .seealso: DMPlexCreate(), DMPlexGetChart()
1131 @*/
1132 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1133 {
1134   DM_Plex       *mesh = (DM_Plex*) dm->data;
1135   PetscErrorCode ierr;
1136 
1137   PetscFunctionBegin;
1138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1139   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1140   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1141   PetscFunctionReturn(0);
1142 }
1143 
1144 #undef __FUNCT__
1145 #define __FUNCT__ "DMPlexGetConeSize"
1146 /*@
1147   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1148 
1149   Not collective
1150 
1151   Input Parameters:
1152 + mesh - The DMPlex
1153 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1154 
1155   Output Parameter:
1156 . size - The cone size for point p
1157 
1158   Level: beginner
1159 
1160 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1161 @*/
1162 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1163 {
1164   DM_Plex       *mesh = (DM_Plex*) dm->data;
1165   PetscErrorCode ierr;
1166 
1167   PetscFunctionBegin;
1168   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1169   PetscValidPointer(size, 3);
1170   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1171   PetscFunctionReturn(0);
1172 }
1173 
1174 #undef __FUNCT__
1175 #define __FUNCT__ "DMPlexSetConeSize"
1176 /*@
1177   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1178 
1179   Not collective
1180 
1181   Input Parameters:
1182 + mesh - The DMPlex
1183 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1184 - size - The cone size for point p
1185 
1186   Output Parameter:
1187 
1188   Note:
1189   This should be called after DMPlexSetChart().
1190 
1191   Level: beginner
1192 
1193 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1194 @*/
1195 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1196 {
1197   DM_Plex       *mesh = (DM_Plex*) dm->data;
1198   PetscErrorCode ierr;
1199 
1200   PetscFunctionBegin;
1201   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1202   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1203 
1204   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1205   PetscFunctionReturn(0);
1206 }
1207 
1208 #undef __FUNCT__
1209 #define __FUNCT__ "DMPlexGetCone"
1210 /*@C
1211   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1212 
1213   Not collective
1214 
1215   Input Parameters:
1216 + mesh - The DMPlex
1217 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1218 
1219   Output Parameter:
1220 . cone - An array of points which are on the in-edges for point p
1221 
1222   Level: beginner
1223 
1224   Note:
1225   This routine is not available in Fortran.
1226 
1227 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1228 @*/
1229 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1230 {
1231   DM_Plex       *mesh = (DM_Plex*) dm->data;
1232   PetscInt       off;
1233   PetscErrorCode ierr;
1234 
1235   PetscFunctionBegin;
1236   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1237   PetscValidPointer(cone, 3);
1238   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1239   *cone = &mesh->cones[off];
1240   PetscFunctionReturn(0);
1241 }
1242 
1243 #undef __FUNCT__
1244 #define __FUNCT__ "DMPlexSetCone"
1245 /*@
1246   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1247 
1248   Not collective
1249 
1250   Input Parameters:
1251 + mesh - The DMPlex
1252 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1253 - cone - An array of points which are on the in-edges for point p
1254 
1255   Output Parameter:
1256 
1257   Note:
1258   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1259 
1260   Level: beginner
1261 
1262 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1263 @*/
1264 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1265 {
1266   DM_Plex       *mesh = (DM_Plex*) dm->data;
1267   PetscInt       pStart, pEnd;
1268   PetscInt       dof, off, c;
1269   PetscErrorCode ierr;
1270 
1271   PetscFunctionBegin;
1272   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1273   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1274   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1275   if (dof) PetscValidPointer(cone, 3);
1276   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1277   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1278   for (c = 0; c < dof; ++c) {
1279     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1280     mesh->cones[off+c] = cone[c];
1281   }
1282   PetscFunctionReturn(0);
1283 }
1284 
1285 #undef __FUNCT__
1286 #define __FUNCT__ "DMPlexGetConeOrientation"
1287 /*@C
1288   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1289 
1290   Not collective
1291 
1292   Input Parameters:
1293 + mesh - The DMPlex
1294 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1295 
1296   Output Parameter:
1297 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1298                     integer giving the prescription for cone traversal. If it is negative, the cone is
1299                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1300                     the index of the cone point on which to start.
1301 
1302   Level: beginner
1303 
1304   Note:
1305   This routine is not available in Fortran.
1306 
1307 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1308 @*/
1309 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1310 {
1311   DM_Plex       *mesh = (DM_Plex*) dm->data;
1312   PetscInt       off;
1313   PetscErrorCode ierr;
1314 
1315   PetscFunctionBegin;
1316   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1317 #if defined(PETSC_USE_DEBUG)
1318   {
1319     PetscInt dof;
1320     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1321     if (dof) PetscValidPointer(coneOrientation, 3);
1322   }
1323 #endif
1324   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1325 
1326   *coneOrientation = &mesh->coneOrientations[off];
1327   PetscFunctionReturn(0);
1328 }
1329 
1330 #undef __FUNCT__
1331 #define __FUNCT__ "DMPlexSetConeOrientation"
1332 /*@
1333   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1334 
1335   Not collective
1336 
1337   Input Parameters:
1338 + mesh - The DMPlex
1339 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1340 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1341                     integer giving the prescription for cone traversal. If it is negative, the cone is
1342                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1343                     the index of the cone point on which to start.
1344 
1345   Output Parameter:
1346 
1347   Note:
1348   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1349 
1350   Level: beginner
1351 
1352 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1353 @*/
1354 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1355 {
1356   DM_Plex       *mesh = (DM_Plex*) dm->data;
1357   PetscInt       pStart, pEnd;
1358   PetscInt       dof, off, c;
1359   PetscErrorCode ierr;
1360 
1361   PetscFunctionBegin;
1362   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1363   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1364   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1365   if (dof) PetscValidPointer(coneOrientation, 3);
1366   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1367   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1368   for (c = 0; c < dof; ++c) {
1369     PetscInt cdof, o = coneOrientation[c];
1370 
1371     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1372     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1373     mesh->coneOrientations[off+c] = o;
1374   }
1375   PetscFunctionReturn(0);
1376 }
1377 
1378 #undef __FUNCT__
1379 #define __FUNCT__ "DMPlexInsertCone"
1380 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1381 {
1382   DM_Plex       *mesh = (DM_Plex*) dm->data;
1383   PetscInt       pStart, pEnd;
1384   PetscInt       dof, off;
1385   PetscErrorCode ierr;
1386 
1387   PetscFunctionBegin;
1388   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1389   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1390   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1391   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1392   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1393   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1394   if (conePos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1395   mesh->cones[off+conePos] = conePoint;
1396   PetscFunctionReturn(0);
1397 }
1398 
1399 #undef __FUNCT__
1400 #define __FUNCT__ "DMPlexGetSupportSize"
1401 /*@
1402   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1403 
1404   Not collective
1405 
1406   Input Parameters:
1407 + mesh - The DMPlex
1408 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1409 
1410   Output Parameter:
1411 . size - The support size for point p
1412 
1413   Level: beginner
1414 
1415 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1416 @*/
1417 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1418 {
1419   DM_Plex       *mesh = (DM_Plex*) dm->data;
1420   PetscErrorCode ierr;
1421 
1422   PetscFunctionBegin;
1423   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1424   PetscValidPointer(size, 3);
1425   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1426   PetscFunctionReturn(0);
1427 }
1428 
1429 #undef __FUNCT__
1430 #define __FUNCT__ "DMPlexSetSupportSize"
1431 /*@
1432   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1433 
1434   Not collective
1435 
1436   Input Parameters:
1437 + mesh - The DMPlex
1438 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1439 - size - The support size for point p
1440 
1441   Output Parameter:
1442 
1443   Note:
1444   This should be called after DMPlexSetChart().
1445 
1446   Level: beginner
1447 
1448 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1449 @*/
1450 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1451 {
1452   DM_Plex       *mesh = (DM_Plex*) dm->data;
1453   PetscErrorCode ierr;
1454 
1455   PetscFunctionBegin;
1456   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1457   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1458 
1459   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1460   PetscFunctionReturn(0);
1461 }
1462 
1463 #undef __FUNCT__
1464 #define __FUNCT__ "DMPlexGetSupport"
1465 /*@C
1466   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1467 
1468   Not collective
1469 
1470   Input Parameters:
1471 + mesh - The DMPlex
1472 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1473 
1474   Output Parameter:
1475 . support - An array of points which are on the out-edges for point p
1476 
1477   Level: beginner
1478 
1479 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1480 @*/
1481 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1482 {
1483   DM_Plex       *mesh = (DM_Plex*) dm->data;
1484   PetscInt       off;
1485   PetscErrorCode ierr;
1486 
1487   PetscFunctionBegin;
1488   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1489   PetscValidPointer(support, 3);
1490   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1491   *support = &mesh->supports[off];
1492   PetscFunctionReturn(0);
1493 }
1494 
1495 #undef __FUNCT__
1496 #define __FUNCT__ "DMPlexSetSupport"
1497 /*@
1498   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1499 
1500   Not collective
1501 
1502   Input Parameters:
1503 + mesh - The DMPlex
1504 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1505 - support - An array of points which are on the in-edges for point p
1506 
1507   Output Parameter:
1508 
1509   Note:
1510   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1511 
1512   Level: beginner
1513 
1514 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1515 @*/
1516 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1517 {
1518   DM_Plex       *mesh = (DM_Plex*) dm->data;
1519   PetscInt       pStart, pEnd;
1520   PetscInt       dof, off, c;
1521   PetscErrorCode ierr;
1522 
1523   PetscFunctionBegin;
1524   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1525   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1526   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1527   if (dof) PetscValidPointer(support, 3);
1528   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1529   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1530   for (c = 0; c < dof; ++c) {
1531     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1532     mesh->supports[off+c] = support[c];
1533   }
1534   PetscFunctionReturn(0);
1535 }
1536 
1537 #undef __FUNCT__
1538 #define __FUNCT__ "DMPlexInsertSupport"
1539 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1540 {
1541   DM_Plex       *mesh = (DM_Plex*) dm->data;
1542   PetscInt       pStart, pEnd;
1543   PetscInt       dof, off;
1544   PetscErrorCode ierr;
1545 
1546   PetscFunctionBegin;
1547   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1548   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1549   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1550   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1551   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1552   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1553   if (supportPos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1554   mesh->supports[off+supportPos] = supportPoint;
1555   PetscFunctionReturn(0);
1556 }
1557 
1558 #undef __FUNCT__
1559 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1560 /*@C
1561   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1562 
1563   Not collective
1564 
1565   Input Parameters:
1566 + mesh - The DMPlex
1567 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1568 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1569 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1570 
1571   Output Parameters:
1572 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1573 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1574 
1575   Note:
1576   If using internal storage (points is NULL on input), each call overwrites the last output.
1577 
1578   Level: beginner
1579 
1580 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1581 @*/
1582 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1583 {
1584   DM_Plex        *mesh = (DM_Plex*) dm->data;
1585   PetscInt       *closure, *fifo;
1586   const PetscInt *tmp = NULL, *tmpO = NULL;
1587   PetscInt        tmpSize, t;
1588   PetscInt        depth       = 0, maxSize;
1589   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1590   PetscErrorCode  ierr;
1591 
1592   PetscFunctionBegin;
1593   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1594   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1595   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1596   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1597   if (*points) {
1598     closure = *points;
1599   } else {
1600     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1601   }
1602   closure[0] = p; closure[1] = 0;
1603   /* This is only 1-level */
1604   if (useCone) {
1605     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1606     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1607     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1608   } else {
1609     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1610     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1611   }
1612   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1613     const PetscInt cp = tmp[t];
1614     const PetscInt co = tmpO ? tmpO[t] : 0;
1615 
1616     closure[closureSize]   = cp;
1617     closure[closureSize+1] = co;
1618     fifo[fifoSize]         = cp;
1619     fifo[fifoSize+1]       = co;
1620   }
1621   while (fifoSize - fifoStart) {
1622     const PetscInt q   = fifo[fifoStart];
1623     const PetscInt o   = fifo[fifoStart+1];
1624     const PetscInt rev = o >= 0 ? 0 : 1;
1625     const PetscInt off = rev ? -(o+1) : o;
1626 
1627     if (useCone) {
1628       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1629       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1630       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1631     } else {
1632       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1633       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1634       tmpO = NULL;
1635     }
1636     for (t = 0; t < tmpSize; ++t) {
1637       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1638       const PetscInt cp = tmp[i];
1639       /* Must propogate orientation */
1640       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1641       PetscInt       c;
1642 
1643       /* Check for duplicate */
1644       for (c = 0; c < closureSize; c += 2) {
1645         if (closure[c] == cp) break;
1646       }
1647       if (c == closureSize) {
1648         closure[closureSize]   = cp;
1649         closure[closureSize+1] = co;
1650         fifo[fifoSize]         = cp;
1651         fifo[fifoSize+1]       = co;
1652         closureSize           += 2;
1653         fifoSize              += 2;
1654       }
1655     }
1656     fifoStart += 2;
1657   }
1658   if (numPoints) *numPoints = closureSize/2;
1659   if (points)    *points    = closure;
1660   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1661   PetscFunctionReturn(0);
1662 }
1663 
1664 #undef __FUNCT__
1665 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1666 /*@C
1667   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1668 
1669   Not collective
1670 
1671   Input Parameters:
1672 + mesh - The DMPlex
1673 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1674 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1675 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1676 
1677   Output Parameters:
1678 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1679 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1680 
1681   Note:
1682   If not using internal storage (points is not NULL on input), this call is unnecessary
1683 
1684   Level: beginner
1685 
1686 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1687 @*/
1688 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1689 {
1690   PetscErrorCode ierr;
1691 
1692   PetscFunctionBegin;
1693   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1694   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1695   PetscFunctionReturn(0);
1696 }
1697 
1698 #undef __FUNCT__
1699 #define __FUNCT__ "DMPlexGetFaces"
1700 /*
1701   DMPlexGetFaces -
1702 
1703   Note: This will only work for cell-vertex meshes.
1704 */
1705 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1706 {
1707   DM_Plex        *mesh = (DM_Plex*) dm->data;
1708   const PetscInt *cone = NULL;
1709   PetscInt        depth = 0, dim, coneSize;
1710   PetscErrorCode  ierr;
1711 
1712   PetscFunctionBegin;
1713   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1714   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1715   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1716   if (depth > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1717   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1718   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1719   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1720   switch (dim) {
1721   case 2:
1722     switch (coneSize) {
1723     case 3:
1724       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1725       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1726       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1727       *numFaces         = 3;
1728       *faceSize         = 2;
1729       *faces            = mesh->facesTmp;
1730       break;
1731     case 4:
1732       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1733       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1734       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1735       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1736       *numFaces         = 4;
1737       *faceSize         = 2;
1738       *faces            = mesh->facesTmp;
1739       break;
1740     default:
1741       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1742     }
1743     break;
1744   case 3:
1745     switch (coneSize) {
1746     case 3:
1747       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1748       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1749       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1750       *numFaces         = 3;
1751       *faceSize         = 2;
1752       *faces            = mesh->facesTmp;
1753       break;
1754     case 4:
1755       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1756       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1757       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1758       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1759       *numFaces         = 4;
1760       *faceSize         = 3;
1761       *faces            = mesh->facesTmp;
1762       break;
1763     default:
1764       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1765     }
1766     break;
1767   default:
1768     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1769   }
1770   PetscFunctionReturn(0);
1771 }
1772 
1773 #undef __FUNCT__
1774 #define __FUNCT__ "DMPlexGetMaxSizes"
1775 /*@
1776   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1777 
1778   Not collective
1779 
1780   Input Parameter:
1781 . mesh - The DMPlex
1782 
1783   Output Parameters:
1784 + maxConeSize - The maximum number of in-edges
1785 - maxSupportSize - The maximum number of out-edges
1786 
1787   Level: beginner
1788 
1789 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1790 @*/
1791 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1792 {
1793   DM_Plex *mesh = (DM_Plex*) dm->data;
1794 
1795   PetscFunctionBegin;
1796   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1797   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1798   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1799   PetscFunctionReturn(0);
1800 }
1801 
1802 #undef __FUNCT__
1803 #define __FUNCT__ "DMSetUp_Plex"
1804 PetscErrorCode DMSetUp_Plex(DM dm)
1805 {
1806   DM_Plex       *mesh = (DM_Plex*) dm->data;
1807   PetscInt       size;
1808   PetscErrorCode ierr;
1809 
1810   PetscFunctionBegin;
1811   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1812   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1813   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1814   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1815   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1816   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1817   if (mesh->maxSupportSize) {
1818     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1819     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1820     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1821   }
1822   PetscFunctionReturn(0);
1823 }
1824 
1825 #undef __FUNCT__
1826 #define __FUNCT__ "DMCreateSubDM_Plex"
1827 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1828 {
1829   PetscSection   section, sectionGlobal;
1830   PetscInt      *subIndices;
1831   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1832   PetscErrorCode ierr;
1833 
1834   PetscFunctionBegin;
1835   if (!numFields) PetscFunctionReturn(0);
1836   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1837   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1838   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1839   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1840   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1841   if (numFields > nF) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1842   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1843   for (p = pStart; p < pEnd; ++p) {
1844     PetscInt gdof;
1845 
1846     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1847     if (gdof > 0) {
1848       for (f = 0; f < numFields; ++f) {
1849         PetscInt fdof, fcdof;
1850 
1851         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1852         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1853         subSize += fdof-fcdof;
1854       }
1855     }
1856   }
1857   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1858   for (p = pStart; p < pEnd; ++p) {
1859     PetscInt gdof, goff;
1860 
1861     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1862     if (gdof > 0) {
1863       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1864       for (f = 0; f < numFields; ++f) {
1865         PetscInt fdof, fcdof, fc, f2, poff = 0;
1866 
1867         /* Can get rid of this loop by storing field information in the global section */
1868         for (f2 = 0; f2 < fields[f]; ++f2) {
1869           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1870           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1871           poff += fdof-fcdof;
1872         }
1873         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1874         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1875         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1876           subIndices[subOff] = goff+poff+fc;
1877         }
1878       }
1879     }
1880   }
1881   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1882   if (subdm) {
1883     PetscSection subsection;
1884     PetscBool    haveNull = PETSC_FALSE;
1885     PetscInt     f, nf = 0;
1886 
1887     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1888     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1889     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1890     for (f = 0; f < numFields; ++f) {
1891       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1892       if ((*subdm)->nullspaceConstructors[f]) {
1893         haveNull = PETSC_TRUE;
1894         nf       = f;
1895       }
1896     }
1897     if (haveNull) {
1898       MatNullSpace nullSpace;
1899 
1900       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1901       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1902       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1903     }
1904     if (dm->fields) {
1905       if (nF != dm->numFields) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1906       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1907       for (f = 0; f < numFields; ++f) {
1908         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1909       }
1910       if (numFields == 1) {
1911         MatNullSpace space;
1912         Mat          pmat;
1913 
1914         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1915         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1916         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1917         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1918         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1919         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1920       }
1921     }
1922   }
1923   PetscFunctionReturn(0);
1924 }
1925 
1926 #undef __FUNCT__
1927 #define __FUNCT__ "DMPlexSymmetrize"
1928 /*@
1929   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1930 
1931   Not collective
1932 
1933   Input Parameter:
1934 . mesh - The DMPlex
1935 
1936   Output Parameter:
1937 
1938   Note:
1939   This should be called after all calls to DMPlexSetCone()
1940 
1941   Level: beginner
1942 
1943 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1944 @*/
1945 PetscErrorCode DMPlexSymmetrize(DM dm)
1946 {
1947   DM_Plex       *mesh = (DM_Plex*) dm->data;
1948   PetscInt      *offsets;
1949   PetscInt       supportSize;
1950   PetscInt       pStart, pEnd, p;
1951   PetscErrorCode ierr;
1952 
1953   PetscFunctionBegin;
1954   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1955   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1956   /* Calculate support sizes */
1957   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1958   for (p = pStart; p < pEnd; ++p) {
1959     PetscInt dof, off, c;
1960 
1961     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1962     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1963     for (c = off; c < off+dof; ++c) {
1964       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1965     }
1966   }
1967   for (p = pStart; p < pEnd; ++p) {
1968     PetscInt dof;
1969 
1970     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1971 
1972     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1973   }
1974   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1975   /* Calculate supports */
1976   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1977   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1978   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1979   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1980   for (p = pStart; p < pEnd; ++p) {
1981     PetscInt dof, off, c;
1982 
1983     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1984     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1985     for (c = off; c < off+dof; ++c) {
1986       const PetscInt q = mesh->cones[c];
1987       PetscInt       offS;
1988 
1989       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1990 
1991       mesh->supports[offS+offsets[q]] = p;
1992       ++offsets[q];
1993     }
1994   }
1995   ierr = PetscFree(offsets);CHKERRQ(ierr);
1996   PetscFunctionReturn(0);
1997 }
1998 
1999 #undef __FUNCT__
2000 #define __FUNCT__ "DMPlexSetDepth_Private"
2001 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
2002 {
2003   PetscInt       d;
2004   PetscErrorCode ierr;
2005 
2006   PetscFunctionBegin;
2007   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
2008   if (d < 0) {
2009     /* We are guaranteed that the point has a cone since the depth was not yet set */
2010     const PetscInt *cone = NULL;
2011     PetscInt        dCone;
2012 
2013     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2014     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2015     d    = dCone+1;
2016     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2017   }
2018   *depth = d;
2019   PetscFunctionReturn(0);
2020 }
2021 
2022 #undef __FUNCT__
2023 #define __FUNCT__ "DMPlexStratify"
2024 /*@
2025   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2026   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2027   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2028   the DAG.
2029 
2030   Not collective
2031 
2032   Input Parameter:
2033 . mesh - The DMPlex
2034 
2035   Output Parameter:
2036 
2037   Notes:
2038   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2039   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2040 
2041   This should be called after all calls to DMPlexSymmetrize()
2042 
2043   Level: beginner
2044 
2045 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2046 @*/
2047 PetscErrorCode DMPlexStratify(DM dm)
2048 {
2049   DM_Plex       *mesh = (DM_Plex*) dm->data;
2050   PetscInt       pStart, pEnd, p;
2051   PetscInt       numRoots = 0, numLeaves = 0;
2052   PetscErrorCode ierr;
2053 
2054   PetscFunctionBegin;
2055   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2056   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2057   /* Calculate depth */
2058   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2059   /* Initialize roots and count leaves */
2060   for (p = pStart; p < pEnd; ++p) {
2061     PetscInt coneSize, supportSize;
2062 
2063     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2064     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2065     if (!coneSize && supportSize) {
2066       ++numRoots;
2067       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2068     } else if (!supportSize && coneSize) {
2069       ++numLeaves;
2070     } else if (!supportSize && !coneSize) {
2071       /* Isolated points */
2072       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2073     }
2074   }
2075   if (numRoots + numLeaves == (pEnd - pStart)) {
2076     for (p = pStart; p < pEnd; ++p) {
2077       PetscInt coneSize, supportSize;
2078 
2079       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2080       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2081       if (!supportSize && coneSize) {
2082         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2083       }
2084     }
2085   } else {
2086     /* This might be slow since lookup is not fast */
2087     for (p = pStart; p < pEnd; ++p) {
2088       PetscInt depth;
2089 
2090       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2091     }
2092   }
2093   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2094   PetscFunctionReturn(0);
2095 }
2096 
2097 #undef __FUNCT__
2098 #define __FUNCT__ "DMPlexGetJoin"
2099 /*@C
2100   DMPlexGetJoin - Get an array for the join of the set of points
2101 
2102   Not Collective
2103 
2104   Input Parameters:
2105 + dm - The DMPlex object
2106 . numPoints - The number of input points for the join
2107 - points - The input points
2108 
2109   Output Parameters:
2110 + numCoveredPoints - The number of points in the join
2111 - coveredPoints - The points in the join
2112 
2113   Level: intermediate
2114 
2115   Note: Currently, this is restricted to a single level join
2116 
2117 .keywords: mesh
2118 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2119 @*/
2120 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2121 {
2122   DM_Plex       *mesh = (DM_Plex*) dm->data;
2123   PetscInt      *join[2];
2124   PetscInt       joinSize, i = 0;
2125   PetscInt       dof, off, p, c, m;
2126   PetscErrorCode ierr;
2127 
2128   PetscFunctionBegin;
2129   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2130   PetscValidPointer(points, 2);
2131   PetscValidPointer(numCoveredPoints, 3);
2132   PetscValidPointer(coveredPoints, 4);
2133   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2134   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2135   /* Copy in support of first point */
2136   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2137   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2138   for (joinSize = 0; joinSize < dof; ++joinSize) {
2139     join[i][joinSize] = mesh->supports[off+joinSize];
2140   }
2141   /* Check each successive support */
2142   for (p = 1; p < numPoints; ++p) {
2143     PetscInt newJoinSize = 0;
2144 
2145     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2146     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2147     for (c = 0; c < dof; ++c) {
2148       const PetscInt point = mesh->supports[off+c];
2149 
2150       for (m = 0; m < joinSize; ++m) {
2151         if (point == join[i][m]) {
2152           join[1-i][newJoinSize++] = point;
2153           break;
2154         }
2155       }
2156     }
2157     joinSize = newJoinSize;
2158     i        = 1-i;
2159   }
2160   *numCoveredPoints = joinSize;
2161   *coveredPoints    = join[i];
2162   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2163   PetscFunctionReturn(0);
2164 }
2165 
2166 #undef __FUNCT__
2167 #define __FUNCT__ "DMPlexRestoreJoin"
2168 /*@C
2169   DMPlexRestoreJoin - Restore an array for the join of the set of points
2170 
2171   Not Collective
2172 
2173   Input Parameters:
2174 + dm - The DMPlex object
2175 . numPoints - The number of input points for the join
2176 - points - The input points
2177 
2178   Output Parameters:
2179 + numCoveredPoints - The number of points in the join
2180 - coveredPoints - The points in the join
2181 
2182   Level: intermediate
2183 
2184 .keywords: mesh
2185 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2186 @*/
2187 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2188 {
2189   PetscErrorCode ierr;
2190 
2191   PetscFunctionBegin;
2192   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2193   PetscValidPointer(coveredPoints, 4);
2194   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2195   PetscFunctionReturn(0);
2196 }
2197 
2198 #undef __FUNCT__
2199 #define __FUNCT__ "DMPlexGetFullJoin"
2200 /*@C
2201   DMPlexGetFullJoin - Get an array for the join of the set of points
2202 
2203   Not Collective
2204 
2205   Input Parameters:
2206 + dm - The DMPlex object
2207 . numPoints - The number of input points for the join
2208 - points - The input points
2209 
2210   Output Parameters:
2211 + numCoveredPoints - The number of points in the join
2212 - coveredPoints - The points in the join
2213 
2214   Level: intermediate
2215 
2216 .keywords: mesh
2217 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2218 @*/
2219 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2220 {
2221   DM_Plex       *mesh = (DM_Plex*) dm->data;
2222   PetscInt      *offsets, **closures;
2223   PetscInt      *join[2];
2224   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2225   PetscInt       p, d, c, m;
2226   PetscErrorCode ierr;
2227 
2228   PetscFunctionBegin;
2229   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2230   PetscValidPointer(points, 2);
2231   PetscValidPointer(numCoveredPoints, 3);
2232   PetscValidPointer(coveredPoints, 4);
2233 
2234   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2235   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2236   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2237   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2238   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2239   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2240   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2241 
2242   for (p = 0; p < numPoints; ++p) {
2243     PetscInt closureSize;
2244 
2245     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2246 
2247     offsets[p*(depth+2)+0] = 0;
2248     for (d = 0; d < depth+1; ++d) {
2249       PetscInt pStart, pEnd, i;
2250 
2251       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2252       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2253         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2254           offsets[p*(depth+2)+d+1] = i;
2255           break;
2256         }
2257       }
2258       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2259     }
2260     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2261   }
2262   for (d = 0; d < depth+1; ++d) {
2263     PetscInt dof;
2264 
2265     /* Copy in support of first point */
2266     dof = offsets[d+1] - offsets[d];
2267     for (joinSize = 0; joinSize < dof; ++joinSize) {
2268       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2269     }
2270     /* Check each successive cone */
2271     for (p = 1; p < numPoints && joinSize; ++p) {
2272       PetscInt newJoinSize = 0;
2273 
2274       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2275       for (c = 0; c < dof; ++c) {
2276         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2277 
2278         for (m = 0; m < joinSize; ++m) {
2279           if (point == join[i][m]) {
2280             join[1-i][newJoinSize++] = point;
2281             break;
2282           }
2283         }
2284       }
2285       joinSize = newJoinSize;
2286       i        = 1-i;
2287     }
2288     if (joinSize) break;
2289   }
2290   *numCoveredPoints = joinSize;
2291   *coveredPoints    = join[i];
2292   for (p = 0; p < numPoints; ++p) {
2293     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2294   }
2295   ierr = PetscFree(closures);CHKERRQ(ierr);
2296   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2297   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2298   PetscFunctionReturn(0);
2299 }
2300 
2301 #undef __FUNCT__
2302 #define __FUNCT__ "DMPlexGetMeet"
2303 /*@C
2304   DMPlexGetMeet - Get an array for the meet of the set of points
2305 
2306   Not Collective
2307 
2308   Input Parameters:
2309 + dm - The DMPlex object
2310 . numPoints - The number of input points for the meet
2311 - points - The input points
2312 
2313   Output Parameters:
2314 + numCoveredPoints - The number of points in the meet
2315 - coveredPoints - The points in the meet
2316 
2317   Level: intermediate
2318 
2319   Note: Currently, this is restricted to a single level meet
2320 
2321 .keywords: mesh
2322 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2323 @*/
2324 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2325 {
2326   DM_Plex       *mesh = (DM_Plex*) dm->data;
2327   PetscInt      *meet[2];
2328   PetscInt       meetSize, i = 0;
2329   PetscInt       dof, off, p, c, m;
2330   PetscErrorCode ierr;
2331 
2332   PetscFunctionBegin;
2333   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2334   PetscValidPointer(points, 2);
2335   PetscValidPointer(numCoveringPoints, 3);
2336   PetscValidPointer(coveringPoints, 4);
2337   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2338   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2339   /* Copy in cone of first point */
2340   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2341   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2342   for (meetSize = 0; meetSize < dof; ++meetSize) {
2343     meet[i][meetSize] = mesh->cones[off+meetSize];
2344   }
2345   /* Check each successive cone */
2346   for (p = 1; p < numPoints; ++p) {
2347     PetscInt newMeetSize = 0;
2348 
2349     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2350     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2351     for (c = 0; c < dof; ++c) {
2352       const PetscInt point = mesh->cones[off+c];
2353 
2354       for (m = 0; m < meetSize; ++m) {
2355         if (point == meet[i][m]) {
2356           meet[1-i][newMeetSize++] = point;
2357           break;
2358         }
2359       }
2360     }
2361     meetSize = newMeetSize;
2362     i        = 1-i;
2363   }
2364   *numCoveringPoints = meetSize;
2365   *coveringPoints    = meet[i];
2366   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2367   PetscFunctionReturn(0);
2368 }
2369 
2370 #undef __FUNCT__
2371 #define __FUNCT__ "DMPlexRestoreMeet"
2372 /*@C
2373   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2374 
2375   Not Collective
2376 
2377   Input Parameters:
2378 + dm - The DMPlex object
2379 . numPoints - The number of input points for the meet
2380 - points - The input points
2381 
2382   Output Parameters:
2383 + numCoveredPoints - The number of points in the meet
2384 - coveredPoints - The points in the meet
2385 
2386   Level: intermediate
2387 
2388 .keywords: mesh
2389 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2390 @*/
2391 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2392 {
2393   PetscErrorCode ierr;
2394 
2395   PetscFunctionBegin;
2396   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2397   PetscValidPointer(coveredPoints, 4);
2398   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2399   PetscFunctionReturn(0);
2400 }
2401 
2402 #undef __FUNCT__
2403 #define __FUNCT__ "DMPlexGetFullMeet"
2404 /*@C
2405   DMPlexGetFullMeet - Get an array for the meet of the set of points
2406 
2407   Not Collective
2408 
2409   Input Parameters:
2410 + dm - The DMPlex object
2411 . numPoints - The number of input points for the meet
2412 - points - The input points
2413 
2414   Output Parameters:
2415 + numCoveredPoints - The number of points in the meet
2416 - coveredPoints - The points in the meet
2417 
2418   Level: intermediate
2419 
2420 .keywords: mesh
2421 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2422 @*/
2423 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2424 {
2425   DM_Plex       *mesh = (DM_Plex*) dm->data;
2426   PetscInt      *offsets, **closures;
2427   PetscInt      *meet[2];
2428   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2429   PetscInt       p, h, c, m;
2430   PetscErrorCode ierr;
2431 
2432   PetscFunctionBegin;
2433   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2434   PetscValidPointer(points, 2);
2435   PetscValidPointer(numCoveredPoints, 3);
2436   PetscValidPointer(coveredPoints, 4);
2437 
2438   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2439   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2440   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2441   maxSize = PetscPowInt(mesh->maxConeSize,height);
2442   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2443   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2444 
2445   for (p = 0; p < numPoints; ++p) {
2446     PetscInt closureSize;
2447 
2448     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2449 
2450     offsets[p*(height+2)+0] = 0;
2451     for (h = 0; h < height+1; ++h) {
2452       PetscInt pStart, pEnd, i;
2453 
2454       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2455       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2456         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2457           offsets[p*(height+2)+h+1] = i;
2458           break;
2459         }
2460       }
2461       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2462     }
2463     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2464   }
2465   for (h = 0; h < height+1; ++h) {
2466     PetscInt dof;
2467 
2468     /* Copy in cone of first point */
2469     dof = offsets[h+1] - offsets[h];
2470     for (meetSize = 0; meetSize < dof; ++meetSize) {
2471       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2472     }
2473     /* Check each successive cone */
2474     for (p = 1; p < numPoints && meetSize; ++p) {
2475       PetscInt newMeetSize = 0;
2476 
2477       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2478       for (c = 0; c < dof; ++c) {
2479         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2480 
2481         for (m = 0; m < meetSize; ++m) {
2482           if (point == meet[i][m]) {
2483             meet[1-i][newMeetSize++] = point;
2484             break;
2485           }
2486         }
2487       }
2488       meetSize = newMeetSize;
2489       i        = 1-i;
2490     }
2491     if (meetSize) break;
2492   }
2493   *numCoveredPoints = meetSize;
2494   *coveredPoints    = meet[i];
2495   for (p = 0; p < numPoints; ++p) {
2496     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2497   }
2498   ierr = PetscFree(closures);CHKERRQ(ierr);
2499   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2500   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2501   PetscFunctionReturn(0);
2502 }
2503 
2504 #undef __FUNCT__
2505 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2506 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2507 {
2508   MPI_Comm       comm;
2509   PetscInt       cellDim;
2510   PetscErrorCode ierr;
2511 
2512   PetscFunctionBegin;
2513   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2514   PetscValidPointer(numFaceVertices,3);
2515   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2516   switch (cellDim) {
2517   case 0:
2518     *numFaceVertices = 0;
2519     break;
2520   case 1:
2521     *numFaceVertices = 1;
2522     break;
2523   case 2:
2524     switch (numCorners) {
2525     case 3: /* triangle */
2526       *numFaceVertices = 2; /* Edge has 2 vertices */
2527       break;
2528     case 4: /* quadrilateral */
2529       *numFaceVertices = 2; /* Edge has 2 vertices */
2530       break;
2531     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2532       *numFaceVertices = 3; /* Edge has 3 vertices */
2533       break;
2534     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2535       *numFaceVertices = 3; /* Edge has 3 vertices */
2536       break;
2537     default:
2538       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2539     }
2540     break;
2541   case 3:
2542     switch (numCorners) {
2543     case 4: /* tetradehdron */
2544       *numFaceVertices = 3; /* Face has 3 vertices */
2545       break;
2546     case 6: /* tet cohesive cells */
2547       *numFaceVertices = 4; /* Face has 4 vertices */
2548       break;
2549     case 8: /* hexahedron */
2550       *numFaceVertices = 4; /* Face has 4 vertices */
2551       break;
2552     case 9: /* tet cohesive Lagrange cells */
2553       *numFaceVertices = 6; /* Face has 6 vertices */
2554       break;
2555     case 10: /* quadratic tetrahedron */
2556       *numFaceVertices = 6; /* Face has 6 vertices */
2557       break;
2558     case 12: /* hex cohesive Lagrange cells */
2559       *numFaceVertices = 6; /* Face has 6 vertices */
2560       break;
2561     case 18: /* quadratic tet cohesive Lagrange cells */
2562       *numFaceVertices = 6; /* Face has 6 vertices */
2563       break;
2564     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2565       *numFaceVertices = 9; /* Face has 9 vertices */
2566       break;
2567     default:
2568       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2569     }
2570     break;
2571   default:
2572     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2573   }
2574   PetscFunctionReturn(0);
2575 }
2576 
2577 #undef __FUNCT__
2578 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2579 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2580 {
2581   const PetscInt maxFaceCases = 30;
2582   PetscInt       numFaceCases = 0;
2583   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2584   PetscInt      *off, *adj;
2585   PetscInt      *neighborCells, *tmpClosure;
2586   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2587   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2588   PetscErrorCode ierr;
2589 
2590   PetscFunctionBegin;
2591   /* For parallel partitioning, I think you have to communicate supports */
2592   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2593   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2594   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2595   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2596   if (cEnd - cStart == 0) {
2597     if (numVertices) *numVertices = 0;
2598     if (offsets)   *offsets   = NULL;
2599     if (adjacency) *adjacency = NULL;
2600     PetscFunctionReturn(0);
2601   }
2602   numCells = cEnd - cStart;
2603   /* Setup face recognition */
2604   if (depth == 1) {
2605     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 */
2606 
2607     for (c = cStart; c < cEnd; ++c) {
2608       PetscInt corners;
2609 
2610       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2611       if (!cornersSeen[corners]) {
2612         PetscInt nFV;
2613 
2614         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2615         cornersSeen[corners] = 1;
2616 
2617         ierr = DMPlexGetNumFaceVertices_Internal(dm, corners, &nFV);CHKERRQ(ierr);
2618 
2619         numFaceVertices[numFaceCases++] = nFV;
2620       }
2621     }
2622   }
2623   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2624   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2625   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2626   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2627   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2628   /* Count neighboring cells */
2629   for (cell = cStart; cell < cEnd; ++cell) {
2630     PetscInt numNeighbors = maxNeighbors, n;
2631 
2632     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2633     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2634     for (n = 0; n < numNeighbors; ++n) {
2635       PetscInt        cellPair[2];
2636       PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2637       PetscInt        meetSize = 0;
2638       const PetscInt *meet    = NULL;
2639 
2640       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2641       if (cellPair[0] == cellPair[1]) continue;
2642       if (!found) {
2643         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2644         if (meetSize) {
2645           PetscInt f;
2646 
2647           for (f = 0; f < numFaceCases; ++f) {
2648             if (numFaceVertices[f] == meetSize) {
2649               found = PETSC_TRUE;
2650               break;
2651             }
2652           }
2653         }
2654         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2655       }
2656       if (found) ++off[cell-cStart+1];
2657     }
2658   }
2659   /* Prefix sum */
2660   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2661 
2662   if (adjacency) {
2663     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2664     /* Get neighboring cells */
2665     for (cell = cStart; cell < cEnd; ++cell) {
2666       PetscInt numNeighbors = maxNeighbors, n;
2667       PetscInt cellOffset   = 0;
2668 
2669       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2670       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2671       for (n = 0; n < numNeighbors; ++n) {
2672         PetscInt        cellPair[2];
2673         PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2674         PetscInt        meetSize = 0;
2675         const PetscInt *meet    = NULL;
2676 
2677         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2678         if (cellPair[0] == cellPair[1]) continue;
2679         if (!found) {
2680           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2681           if (meetSize) {
2682             PetscInt f;
2683 
2684             for (f = 0; f < numFaceCases; ++f) {
2685               if (numFaceVertices[f] == meetSize) {
2686                 found = PETSC_TRUE;
2687                 break;
2688               }
2689             }
2690           }
2691           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2692         }
2693         if (found) {
2694           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2695           ++cellOffset;
2696         }
2697       }
2698     }
2699   }
2700   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2701   if (numVertices) *numVertices = numCells;
2702   if (offsets)   *offsets   = off;
2703   if (adjacency) *adjacency = adj;
2704   PetscFunctionReturn(0);
2705 }
2706 
2707 #if defined(PETSC_HAVE_CHACO)
2708 #if defined(PETSC_HAVE_UNISTD_H)
2709 #include <unistd.h>
2710 #endif
2711 /* Chaco does not have an include file */
2712 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2713                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2714                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2715                        int mesh_dims[3], double *goal, int global_method, int local_method,
2716                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2717 
2718 extern int FREE_GRAPH;
2719 
2720 #undef __FUNCT__
2721 #define __FUNCT__ "DMPlexPartition_Chaco"
2722 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2723 {
2724   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2725   MPI_Comm       comm;
2726   int            nvtxs          = numVertices; /* number of vertices in full graph */
2727   int           *vwgts          = NULL;   /* weights for all vertices */
2728   float         *ewgts          = NULL;   /* weights for all edges */
2729   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2730   char          *outassignname  = NULL;   /*  name of assignment output file */
2731   char          *outfilename    = NULL;   /* output file name */
2732   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2733   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2734   int            mesh_dims[3];            /* dimensions of mesh of processors */
2735   double        *goal          = NULL;    /* desired set sizes for each set */
2736   int            global_method = 1;       /* global partitioning algorithm */
2737   int            local_method  = 1;       /* local partitioning algorithm */
2738   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2739   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2740   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2741   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2742   long           seed          = 123636512; /* for random graph mutations */
2743   short int     *assignment;              /* Output partition */
2744   int            fd_stdout, fd_pipe[2];
2745   PetscInt      *points;
2746   PetscMPIInt    commSize;
2747   int            i, v, p;
2748   PetscErrorCode ierr;
2749 
2750   PetscFunctionBegin;
2751   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2752   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2753   if (!numVertices) {
2754     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2755     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2756     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2757     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2758     PetscFunctionReturn(0);
2759   }
2760   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2761   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2762 
2763   if (global_method == INERTIAL_METHOD) {
2764     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2765     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2766   }
2767   mesh_dims[0] = commSize;
2768   mesh_dims[1] = 1;
2769   mesh_dims[2] = 1;
2770   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2771   /* Chaco outputs to stdout. We redirect this to a buffer. */
2772   /* TODO: check error codes for UNIX calls */
2773 #if defined(PETSC_HAVE_UNISTD_H)
2774   {
2775     int piperet;
2776     piperet = pipe(fd_pipe);
2777     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2778     fd_stdout = dup(1);
2779     close(1);
2780     dup2(fd_pipe[1], 1);
2781   }
2782 #endif
2783   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2784                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2785                    vmax, ndims, eigtol, seed);
2786 #if defined(PETSC_HAVE_UNISTD_H)
2787   {
2788     char msgLog[10000];
2789     int  count;
2790 
2791     fflush(stdout);
2792     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2793     if (count < 0) count = 0;
2794     msgLog[count] = 0;
2795     close(1);
2796     dup2(fd_stdout, 1);
2797     close(fd_stdout);
2798     close(fd_pipe[0]);
2799     close(fd_pipe[1]);
2800     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2801   }
2802 #endif
2803   /* Convert to PetscSection+IS */
2804   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2805   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2806   for (v = 0; v < nvtxs; ++v) {
2807     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2808   }
2809   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2810   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2811   for (p = 0, i = 0; p < commSize; ++p) {
2812     for (v = 0; v < nvtxs; ++v) {
2813       if (assignment[v] == p) points[i++] = v;
2814     }
2815   }
2816   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2817   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2818   if (global_method == INERTIAL_METHOD) {
2819     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2820   }
2821   ierr = PetscFree(assignment);CHKERRQ(ierr);
2822   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2823   PetscFunctionReturn(0);
2824 }
2825 #endif
2826 
2827 #if defined(PETSC_HAVE_PARMETIS)
2828 #undef __FUNCT__
2829 #define __FUNCT__ "DMPlexPartition_ParMetis"
2830 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2831 {
2832   PetscFunctionBegin;
2833   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2834   PetscFunctionReturn(0);
2835 }
2836 #endif
2837 
2838 #undef __FUNCT__
2839 #define __FUNCT__ "DMPlexEnlargePartition"
2840 /* Expand the partition by BFS on the adjacency graph */
2841 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2842 {
2843   PetscHashI      h;
2844   const PetscInt *points;
2845   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2846   PetscInt        pStart, pEnd, part, q;
2847   PetscErrorCode  ierr;
2848 
2849   PetscFunctionBegin;
2850   PetscHashICreate(h);
2851   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2852   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2853   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2854   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2855   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2856   for (part = pStart; part < pEnd; ++part) {
2857     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2858 
2859     PetscHashIClear(h);
2860     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2861     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2862     /* Add all existing points to h */
2863     for (p = 0; p < numPoints; ++p) {
2864       const PetscInt point = points[off+p];
2865       PetscHashIAdd(h, point, 1);
2866     }
2867     PetscHashISize(h, nP);
2868     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2869     /* Add all points in next BFS level */
2870     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2871     for (p = 0; p < numPoints; ++p) {
2872       const PetscInt point = points[off+p];
2873       PetscInt       s     = start[point], e = start[point+1], a;
2874 
2875       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2876     }
2877     PetscHashISize(h, numNewPoints);
2878     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2879     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2880     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2881     totPoints += numNewPoints;
2882   }
2883   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2884   PetscHashIDestroy(h);
2885   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2886   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2887   for (part = pStart, q = 0; part < pEnd; ++part) {
2888     PetscInt numPoints, p;
2889 
2890     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2891     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2892     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2893   }
2894   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2895   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2896   PetscFunctionReturn(0);
2897 }
2898 
2899 #undef __FUNCT__
2900 #define __FUNCT__ "DMPlexCreatePartition"
2901 /*
2902   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2903 
2904   Collective on DM
2905 
2906   Input Parameters:
2907   + dm - The DM
2908   . height - The height for points in the partition
2909   - enlarge - Expand each partition with neighbors
2910 
2911   Output Parameters:
2912   + partSection - The PetscSection giving the division of points by partition
2913   . partition - The list of points by partition
2914   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2915   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2916 
2917   Level: developer
2918 
2919 .seealso DMPlexDistribute()
2920 */
2921 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2922 {
2923   PetscMPIInt    size;
2924   PetscErrorCode ierr;
2925 
2926   PetscFunctionBegin;
2927   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2928 
2929   *origPartSection = NULL;
2930   *origPartition   = NULL;
2931   if (size == 1) {
2932     PetscInt *points;
2933     PetscInt  cStart, cEnd, c;
2934 
2935     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2936     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2937     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2938     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2939     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2940     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2941     for (c = cStart; c < cEnd; ++c) points[c] = c;
2942     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2943     PetscFunctionReturn(0);
2944   }
2945   if (height == 0) {
2946     PetscInt  numVertices;
2947     PetscInt *start     = NULL;
2948     PetscInt *adjacency = NULL;
2949 
2950     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2951     if (1) {
2952 #if defined(PETSC_HAVE_CHACO)
2953       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2954 #endif
2955     } else {
2956 #if defined(PETSC_HAVE_PARMETIS)
2957       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2958 #endif
2959     }
2960     if (enlarge) {
2961       *origPartSection = *partSection;
2962       *origPartition   = *partition;
2963 
2964       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2965     }
2966     ierr = PetscFree(start);CHKERRQ(ierr);
2967     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2968 # if 0
2969   } else if (height == 1) {
2970     /* Build the dual graph for faces and partition the hypergraph */
2971     PetscInt numEdges;
2972 
2973     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2974     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2975     destroyCSR(numEdges, start, adjacency);
2976 #endif
2977   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2978   PetscFunctionReturn(0);
2979 }
2980 
2981 #undef __FUNCT__
2982 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2983 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2984 {
2985   /* const PetscInt  height = 0; */
2986   const PetscInt *partArray;
2987   PetscInt       *allPoints, *partPoints = NULL;
2988   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2989   PetscErrorCode  ierr;
2990 
2991   PetscFunctionBegin;
2992   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2993   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2994   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2995   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2996   for (rank = rStart; rank < rEnd; ++rank) {
2997     PetscInt partSize = 0;
2998     PetscInt numPoints, offset, p;
2999 
3000     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3001     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3002     for (p = 0; p < numPoints; ++p) {
3003       PetscInt  point   = partArray[offset+p], closureSize, c;
3004       PetscInt *closure = NULL;
3005 
3006       /* TODO Include support for height > 0 case */
3007       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3008       /* Merge into existing points */
3009       if (partSize+closureSize > maxPartSize) {
3010         PetscInt *tmpPoints;
3011 
3012         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3013         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3014         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3015         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3016 
3017         partPoints = tmpPoints;
3018       }
3019       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3020       partSize += closureSize;
3021 
3022       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3023       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3024     }
3025     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3026   }
3027   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3028   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3029   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3030 
3031   for (rank = rStart; rank < rEnd; ++rank) {
3032     PetscInt partSize = 0, newOffset;
3033     PetscInt numPoints, offset, p;
3034 
3035     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3036     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3037     for (p = 0; p < numPoints; ++p) {
3038       PetscInt  point   = partArray[offset+p], closureSize, c;
3039       PetscInt *closure = NULL;
3040 
3041       /* TODO Include support for height > 0 case */
3042       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3043       /* Merge into existing points */
3044       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3045       partSize += closureSize;
3046 
3047       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3048       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3049     }
3050     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3051     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3052   }
3053   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3054   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3055   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3056   PetscFunctionReturn(0);
3057 }
3058 
3059 #undef __FUNCT__
3060 #define __FUNCT__ "DMPlexDistributeField"
3061 /*
3062   Input Parameters:
3063 . originalSection
3064 , originalVec
3065 
3066   Output Parameters:
3067 . newSection
3068 . newVec
3069 */
3070 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3071 {
3072   PetscSF        fieldSF;
3073   PetscInt      *remoteOffsets, fieldSize;
3074   PetscScalar   *originalValues, *newValues;
3075   PetscErrorCode ierr;
3076 
3077   PetscFunctionBegin;
3078   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3079 
3080   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3081   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3082   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3083 
3084   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3085   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3086   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3087   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3088   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3089   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3090   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3091   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3092   PetscFunctionReturn(0);
3093 }
3094 
3095 #undef __FUNCT__
3096 #define __FUNCT__ "DMPlexDistribute"
3097 /*@C
3098   DMPlexDistribute - Distributes the mesh and any associated sections.
3099 
3100   Not Collective
3101 
3102   Input Parameter:
3103 + dm  - The original DMPlex object
3104 . partitioner - The partitioning package, or NULL for the default
3105 - overlap - The overlap of partitions, 0 is the default
3106 
3107   Output Parameter:
3108 . parallelMesh - The distributed DMPlex object, or NULL
3109 
3110   Note: If the mesh was not distributed, the return value is NULL
3111 
3112   Level: intermediate
3113 
3114 .keywords: mesh, elements
3115 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3116 @*/
3117 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3118 {
3119   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3120   MPI_Comm               comm;
3121   const PetscInt         height = 0;
3122   PetscInt               dim, numRemoteRanks;
3123   IS                     origCellPart,        cellPart,        part;
3124   PetscSection           origCellPartSection, cellPartSection, partSection;
3125   PetscSFNode           *remoteRanks;
3126   PetscSF                partSF, pointSF, coneSF;
3127   ISLocalToGlobalMapping renumbering;
3128   PetscSection           originalConeSection, newConeSection;
3129   PetscInt              *remoteOffsets;
3130   PetscInt              *cones, *newCones, newConesSize;
3131   PetscBool              flg;
3132   PetscMPIInt            rank, numProcs, p;
3133   PetscErrorCode         ierr;
3134 
3135   PetscFunctionBegin;
3136   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3137   PetscValidPointer(dmParallel,4);
3138 
3139   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3140   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3141   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3142   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3143 
3144   *dmParallel = NULL;
3145   if (numProcs == 1) PetscFunctionReturn(0);
3146 
3147   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3148   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3149   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3150   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3151   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3152   if (!rank) numRemoteRanks = numProcs;
3153   else       numRemoteRanks = 0;
3154   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3155   for (p = 0; p < numRemoteRanks; ++p) {
3156     remoteRanks[p].rank  = p;
3157     remoteRanks[p].index = 0;
3158   }
3159   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3160   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3161   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3162   if (flg) {
3163     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3164     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3165     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3166     if (origCellPart) {
3167       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3168       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3169       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3170     }
3171     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3172   }
3173   /* Close the partition over the mesh */
3174   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3175   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3176   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3177   /* Create new mesh */
3178   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3179   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3180   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3181   pmesh = (DM_Plex*) (*dmParallel)->data;
3182   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3183   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3184   if (flg) {
3185     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3186     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3187     ierr = ISView(part, NULL);CHKERRQ(ierr);
3188     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3189     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3190     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3191   }
3192   /* Distribute cone section */
3193   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3194   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3195   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3196   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3197   {
3198     PetscInt pStart, pEnd, p;
3199 
3200     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3201     for (p = pStart; p < pEnd; ++p) {
3202       PetscInt coneSize;
3203       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3204       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3205     }
3206   }
3207   /* Communicate and renumber cones */
3208   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3209   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3210   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3211   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3212   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3213   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3214   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3215   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3216   if (flg) {
3217     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3218     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3219     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3220     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3221     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3222   }
3223   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3224   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3225   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3226   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3227   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3228   /* Create supports and stratify sieve */
3229   {
3230     PetscInt pStart, pEnd;
3231 
3232     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3233     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3234   }
3235   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3236   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3237   /* Distribute Coordinates */
3238   {
3239     PetscSection originalCoordSection, newCoordSection;
3240     Vec          originalCoordinates, newCoordinates;
3241     const char  *name;
3242 
3243     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3244     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3245     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3246     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3247     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3248     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3249 
3250     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3251     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3252     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3253   }
3254   /* Distribute labels */
3255   {
3256     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3257     PetscInt numLabels = 0, l;
3258 
3259     /* Bcast number of labels */
3260     while (next) {
3261       ++numLabels; next = next->next;
3262     }
3263     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3264     next = mesh->labels;
3265     for (l = 0; l < numLabels; ++l) {
3266       DMLabel         newLabel;
3267       const PetscInt *partArray;
3268       char           *name;
3269       PetscInt       *stratumSizes = NULL, *points = NULL;
3270       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3271       PetscInt        nameSize, s, p;
3272       PetscBool       isdepth;
3273       size_t          len = 0;
3274 
3275       /* Bcast name (could filter for no points) */
3276       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3277       nameSize = len;
3278       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3279       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3280       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3281       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3282       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3283       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3284       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3285       newLabel->name = name;
3286       /* Bcast numStrata (could filter for no points in stratum) */
3287       if (!rank) newLabel->numStrata = next->numStrata;
3288       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3289       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3290                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3291                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3292       /* Bcast stratumValues (could filter for no points in stratum) */
3293       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3294       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3295       /* Find size on each process and Scatter */
3296       if (!rank) {
3297         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3298         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3299         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3300         for (s = 0; s < next->numStrata; ++s) {
3301           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3302             const PetscInt point = next->points[p];
3303             PetscInt       proc;
3304 
3305             for (proc = 0; proc < numProcs; ++proc) {
3306               PetscInt dof, off, pPart;
3307 
3308               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3309               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3310               for (pPart = off; pPart < off+dof; ++pPart) {
3311                 if (partArray[pPart] == point) {
3312                   ++stratumSizes[proc*next->numStrata+s];
3313                   break;
3314                 }
3315               }
3316             }
3317           }
3318         }
3319         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3320       }
3321       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3322       /* Calculate stratumOffsets */
3323       newLabel->stratumOffsets[0] = 0;
3324       for (s = 0; s < newLabel->numStrata; ++s) {
3325         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3326       }
3327       /* Pack points and Scatter */
3328       if (!rank) {
3329         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3330         displs[0] = 0;
3331         for (p = 0; p < numProcs; ++p) {
3332           sendcnts[p] = 0;
3333           for (s = 0; s < next->numStrata; ++s) {
3334             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3335           }
3336           offsets[p]  = displs[p];
3337           displs[p+1] = displs[p] + sendcnts[p];
3338         }
3339         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3340         for (s = 0; s < next->numStrata; ++s) {
3341           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3342             const PetscInt point = next->points[p];
3343             PetscInt       proc;
3344 
3345             for (proc = 0; proc < numProcs; ++proc) {
3346               PetscInt dof, off, pPart;
3347 
3348               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3349               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3350               for (pPart = off; pPart < off+dof; ++pPart) {
3351                 if (partArray[pPart] == point) {
3352                   points[offsets[proc]++] = point;
3353                   break;
3354                 }
3355               }
3356             }
3357           }
3358         }
3359       }
3360       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3361       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3362       ierr = PetscFree(points);CHKERRQ(ierr);
3363       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3364       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3365       /* Renumber points */
3366       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3367       /* Sort points */
3368       for (s = 0; s < newLabel->numStrata; ++s) {
3369         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3370       }
3371       /* Insert into list */
3372       if (newNext) newNext->next = newLabel;
3373       else pmesh->labels = newLabel;
3374       newNext = newLabel;
3375       if (!rank) next = next->next;
3376     }
3377   }
3378   /* Cleanup Partition */
3379   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3380   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3381   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3382   ierr = ISDestroy(&part);CHKERRQ(ierr);
3383   /* Create point SF for parallel mesh */
3384   {
3385     const PetscInt *leaves;
3386     PetscSFNode    *remotePoints, *rowners, *lowners;
3387     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3388     PetscInt        pStart, pEnd;
3389 
3390     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3391     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3392     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3393     for (p=0; p<numRoots; p++) {
3394       rowners[p].rank  = -1;
3395       rowners[p].index = -1;
3396     }
3397     if (origCellPart) {
3398       /* Make sure cells in the original partition are not assigned to other procs */
3399       const PetscInt *origCells;
3400 
3401       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3402       for (p = 0; p < numProcs; ++p) {
3403         PetscInt dof, off, d;
3404 
3405         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3406         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3407         for (d = off; d < off+dof; ++d) {
3408           rowners[origCells[d]].rank = p;
3409         }
3410       }
3411       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3412     }
3413     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3414     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3415 
3416     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3417     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3418     for (p = 0; p < numLeaves; ++p) {
3419       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3420         lowners[p].rank  = rank;
3421         lowners[p].index = leaves ? leaves[p] : p;
3422       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3423         lowners[p].rank  = -2;
3424         lowners[p].index = -2;
3425       }
3426     }
3427     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3428       rowners[p].rank  = -3;
3429       rowners[p].index = -3;
3430     }
3431     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3432     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3433     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3434     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3435     for (p = 0; p < numLeaves; ++p) {
3436       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3437       if (lowners[p].rank != rank) ++numGhostPoints;
3438     }
3439     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3440     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3441     for (p = 0, gp = 0; p < numLeaves; ++p) {
3442       if (lowners[p].rank != rank) {
3443         ghostPoints[gp]        = leaves ? leaves[p] : p;
3444         remotePoints[gp].rank  = lowners[p].rank;
3445         remotePoints[gp].index = lowners[p].index;
3446         ++gp;
3447       }
3448     }
3449     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3450     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3451     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3452   }
3453   /* Cleanup */
3454   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3455   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3456   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3457   PetscFunctionReturn(0);
3458 }
3459 
3460 #undef __FUNCT__
3461 #define __FUNCT__ "DMPlexRenumber_Private"
3462 /*
3463   Reasons to renumber:
3464 
3465   1) Permute points, e.g. bandwidth reduction (Renumber)
3466 
3467     a) Must not mix strata
3468 
3469   2) Shift numbers for point insertion (Shift)
3470 
3471     a) Want operation brken into parts so that insertion can be interleaved
3472 
3473   renumbering - An IS which provides the new numbering
3474 */
3475 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3476 {
3477   PetscFunctionBegin;
3478   PetscFunctionReturn(0);
3479 }
3480 
3481 #undef __FUNCT__
3482 #define __FUNCT__ "DMPlexShiftPoint_Private"
3483 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3484 {
3485   if (depth < 0) return p;
3486   /* Cells    */ if (p < depthEnd[depth])   return p;
3487   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3488   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3489   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3490 }
3491 
3492 #undef __FUNCT__
3493 #define __FUNCT__ "DMPlexShiftSizes_Private"
3494 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3495 {
3496   PetscInt      *depthEnd;
3497   PetscInt       depth = 0, d, pStart, pEnd, p;
3498   PetscErrorCode ierr;
3499 
3500   PetscFunctionBegin;
3501   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3502   if (depth < 0) PetscFunctionReturn(0);
3503   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3504   /* Step 1: Expand chart */
3505   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3506   for (d = 0; d <= depth; ++d) {
3507     pEnd += depthShift[d];
3508     ierr  = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3509   }
3510   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3511   /* Step 2: Set cone and support sizes */
3512   for (d = 0; d <= depth; ++d) {
3513     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3514     for (p = pStart; p < pEnd; ++p) {
3515       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3516       PetscInt size;
3517 
3518       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3519       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3520       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3521       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3522     }
3523   }
3524   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3525   PetscFunctionReturn(0);
3526 }
3527 
3528 #undef __FUNCT__
3529 #define __FUNCT__ "DMPlexShiftPoints_Private"
3530 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3531 {
3532   PetscInt      *depthEnd, *newpoints;
3533   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3534   PetscErrorCode ierr;
3535 
3536   PetscFunctionBegin;
3537   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3538   if (depth < 0) PetscFunctionReturn(0);
3539   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3540   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3541   for (d = 0; d <= depth; ++d) {
3542     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3543   }
3544   /* Step 5: Set cones and supports */
3545   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3546   for (p = pStart; p < pEnd; ++p) {
3547     const PetscInt *points = NULL, *orientations = NULL;
3548     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3549 
3550     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3551     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3552     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3553     for (i = 0; i < size; ++i) {
3554       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3555     }
3556     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3557     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3558     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3559     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3560     for (i = 0; i < size; ++i) {
3561       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3562     }
3563     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3564   }
3565   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3566   PetscFunctionReturn(0);
3567 }
3568 
3569 #undef __FUNCT__
3570 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3571 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3572 {
3573   PetscSection   coordSection, newCoordSection;
3574   Vec            coordinates, newCoordinates;
3575   PetscScalar   *coords, *newCoords;
3576   PetscInt      *depthEnd, coordSize;
3577   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3578   PetscErrorCode ierr;
3579 
3580   PetscFunctionBegin;
3581   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3582   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3583   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3584   for (d = 0; d <= depth; ++d) {
3585     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3586   }
3587   /* Step 8: Convert coordinates */
3588   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3589   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3590   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3591   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection);CHKERRQ(ierr);
3592   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3593   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3594   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3595   for (v = vStartNew; v < vEndNew; ++v) {
3596     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3597     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3598   }
3599   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3600   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3601   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3602   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &newCoordinates);CHKERRQ(ierr);
3603   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3604   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3605   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3606   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3607   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3608   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3609   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3610   for (v = vStart; v < vEnd; ++v) {
3611     PetscInt dof, off, noff, d;
3612 
3613     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3614     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3615     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3616     for (d = 0; d < dof; ++d) {
3617       newCoords[noff+d] = coords[off+d];
3618     }
3619   }
3620   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3621   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3622   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3623   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3624   PetscFunctionReturn(0);
3625 }
3626 
3627 #undef __FUNCT__
3628 #define __FUNCT__ "DMPlexShiftSF_Private"
3629 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3630 {
3631   PetscInt          *depthEnd;
3632   PetscInt           depth = 0, d;
3633   PetscSF            sfPoint, sfPointNew;
3634   const PetscSFNode *remotePoints;
3635   PetscSFNode       *gremotePoints;
3636   const PetscInt    *localPoints;
3637   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3638   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3639   PetscMPIInt        numProcs;
3640   PetscErrorCode     ierr;
3641 
3642   PetscFunctionBegin;
3643   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3644   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3645   for (d = 0; d <= depth; ++d) {
3646     totShift += depthShift[d];
3647     ierr      = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3648   }
3649   /* Step 9: Convert pointSF */
3650   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
3651   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3652   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3653   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3654   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3655   if (numRoots >= 0) {
3656     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3657     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3658     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3659     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3660     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3661     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3662     for (l = 0; l < numLeaves; ++l) {
3663       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3664       gremotePoints[l].rank  = remotePoints[l].rank;
3665       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3666     }
3667     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3668     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3669   }
3670   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3671   PetscFunctionReturn(0);
3672 }
3673 
3674 #undef __FUNCT__
3675 #define __FUNCT__ "DMPlexShiftLabels_Private"
3676 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3677 {
3678   PetscSF            sfPoint;
3679   DMLabel            vtkLabel, ghostLabel;
3680   PetscInt          *depthEnd;
3681   const PetscSFNode *leafRemote;
3682   const PetscInt    *leafLocal;
3683   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3684   PetscMPIInt        rank;
3685   PetscErrorCode     ierr;
3686 
3687   PetscFunctionBegin;
3688   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3689   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3690   for (d = 0; d <= depth; ++d) {
3691     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3692   }
3693   /* Step 10: Convert labels */
3694   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3695   for (l = 0; l < numLabels; ++l) {
3696     DMLabel         label, newlabel;
3697     const char     *lname;
3698     PetscBool       isDepth;
3699     IS              valueIS;
3700     const PetscInt *values;
3701     PetscInt        numValues, val;
3702 
3703     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3704     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3705     if (isDepth) continue;
3706     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3707     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3708     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3709     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3710     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3711     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3712     for (val = 0; val < numValues; ++val) {
3713       IS              pointIS;
3714       const PetscInt *points;
3715       PetscInt        numPoints, p;
3716 
3717       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3718       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3719       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3720       for (p = 0; p < numPoints; ++p) {
3721         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3722 
3723         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3724       }
3725       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3726       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3727     }
3728     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3729     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3730   }
3731   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3732   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3733   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
3734   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3735   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3736   ierr = PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3737   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3738   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3739   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3740   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3741   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3742     for (; c < leafLocal[l] && c < cEnd; ++c) {
3743       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3744     }
3745     if (leafLocal[l] >= cEnd) break;
3746     if (leafRemote[l].rank == rank) {
3747       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3748     } else {
3749       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3750     }
3751   }
3752   for (; c < cEnd; ++c) {
3753     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3754   }
3755   if (0) {
3756     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3757     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3758     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3759   }
3760   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3761   for (f = fStart; f < fEnd; ++f) {
3762     PetscInt numCells;
3763 
3764     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3765     if (numCells < 2) {
3766       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3767     } else {
3768       const PetscInt *cells = NULL;
3769       PetscInt        vA, vB;
3770 
3771       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3772       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3773       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3774       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3775     }
3776   }
3777   if (0) {
3778     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3779     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3780     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3781   }
3782   PetscFunctionReturn(0);
3783 }
3784 
3785 #undef __FUNCT__
3786 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3787 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3788 {
3789   DMLabel         label;
3790   IS              valueIS;
3791   const PetscInt *values;
3792   PetscInt       *depthShift;
3793   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3794   PetscErrorCode  ierr;
3795 
3796   PetscFunctionBegin;
3797   /* Count ghost cells */
3798   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3799   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3800   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3801   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3802 
3803   *numGhostCells = 0;
3804   for (fs = 0; fs < numFS; ++fs) {
3805     PetscInt numBdFaces;
3806 
3807     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3808 
3809     *numGhostCells += numBdFaces;
3810   }
3811   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3812   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3813   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3814   if (depth >= 0) depthShift[depth] = *numGhostCells;
3815   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3816   /* Step 3: Set cone/support sizes for new points */
3817   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
3818   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3819     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3820   }
3821   for (fs = 0; fs < numFS; ++fs) {
3822     IS              faceIS;
3823     const PetscInt *faces;
3824     PetscInt        numFaces, f;
3825 
3826     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3827     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3828     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3829     for (f = 0; f < numFaces; ++f) {
3830       PetscInt size;
3831 
3832       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3833       if (size != 1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3834       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3835     }
3836     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3837     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3838   }
3839   /* Step 4: Setup ghosted DM */
3840   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3841   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3842   /* Step 6: Set cones and supports for new points */
3843   ghostCell = cEnd;
3844   for (fs = 0; fs < numFS; ++fs) {
3845     IS              faceIS;
3846     const PetscInt *faces;
3847     PetscInt        numFaces, f;
3848 
3849     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3850     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3851     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3852     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3853       PetscInt newFace = faces[f] + *numGhostCells;
3854 
3855       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3856       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3857     }
3858     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3859     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3860   }
3861   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3862   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3863   /* Step 7: Stratify */
3864   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3865   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3866   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3867   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3868   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3869   PetscFunctionReturn(0);
3870 }
3871 
3872 #undef __FUNCT__
3873 #define __FUNCT__ "DMPlexConstructGhostCells"
3874 /*@C
3875   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3876 
3877   Collective on dm
3878 
3879   Input Parameters:
3880 + dm - The original DM
3881 - labelName - The label specifying the boundary faces (this could be auto-generated)
3882 
3883   Output Parameters:
3884 + numGhostCells - The number of ghost cells added to the DM
3885 - dmGhosted - The new DM
3886 
3887   Level: developer
3888 
3889 .seealso: DMCreate()
3890 */
3891 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3892 {
3893   DM             gdm;
3894   PetscInt       dim;
3895   PetscErrorCode ierr;
3896 
3897   PetscFunctionBegin;
3898   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3899   PetscValidPointer(numGhostCells, 3);
3900   PetscValidPointer(dmGhosted, 4);
3901   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &gdm);CHKERRQ(ierr);
3902   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3903   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3904   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3905   switch (dim) {
3906   case 2:
3907     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3908     break;
3909   default:
3910     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3911   }
3912   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3913   *dmGhosted = gdm;
3914   PetscFunctionReturn(0);
3915 }
3916 
3917 #undef __FUNCT__
3918 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3919 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3920 {
3921   MPI_Comm        comm;
3922   IS              valueIS, *pointIS;
3923   const PetscInt *values, **splitPoints;
3924   PetscSection    coordSection;
3925   Vec             coordinates;
3926   PetscScalar    *coords;
3927   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3928   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3929   PetscErrorCode  ierr;
3930 
3931   PetscFunctionBegin;
3932   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3933   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3934   /* Count split points and add cohesive cells */
3935   if (label) {
3936     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3937     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3938     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3939   }
3940   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3941   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3942   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3943   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3944   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3945   for (d = 0; d <= depth; ++d) {
3946     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3947     numSplitPoints[d] = 0;
3948     splitPoints[d]    = NULL;
3949     pointIS[d]        = NULL;
3950   }
3951   for (sp = 0; sp < numSP; ++sp) {
3952     const PetscInt dep = values[sp];
3953 
3954     if ((dep < 0) || (dep > depth)) continue;
3955     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3956     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3957     if (pointIS[dep]) {
3958       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3959       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3960     }
3961   }
3962   if (depth >= 0) {
3963     /* Calculate number of additional points */
3964     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3965     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3966     /* Calculate hybrid bound for each dimension */
3967     pMaxNew[0] += depthShift[depth];
3968     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3969     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3970 
3971     /* Calculate point offset for each dimension */
3972     depthOffset[depth] = 0;
3973     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3974     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3975     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3976   }
3977   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3978   /* Step 3: Set cone/support sizes for new points */
3979   for (dep = 0; dep <= depth; ++dep) {
3980     for (p = 0; p < numSplitPoints[dep]; ++p) {
3981       const PetscInt  oldp   = splitPoints[dep][p];
3982       const PetscInt  newp   = depthOffset[dep] + oldp;
3983       const PetscInt  splitp = pMaxNew[dep] + p;
3984       const PetscInt *support;
3985       PetscInt        coneSize, supportSize, q, e;
3986 
3987       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3988       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3989       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3990       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3991       if (dep == depth-1) {
3992         const PetscInt ccell = pMaxNew[depth] + p;
3993         /* Add cohesive cells, they are prisms */
3994         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3995       } else if (dep == 0) {
3996         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3997 
3998         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3999         /* Split old vertex: Edges in old split faces and new cohesive edge */
4000         for (e = 0, q = 0; e < supportSize; ++e) {
4001           PetscInt val;
4002 
4003           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4004           if ((val == 1) || (val == (shift + 1))) ++q;
4005         }
4006         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
4007         /* Split new vertex: Edges in new split faces and new cohesive edge */
4008         for (e = 0, q = 0; e < supportSize; ++e) {
4009           PetscInt val;
4010 
4011           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4012           if ((val == 1) || (val == -(shift + 1))) ++q;
4013         }
4014         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
4015         /* Add cohesive edges */
4016         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4017         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4018       } else if (dep == dim-2) {
4019         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4020         /* Split old edge: Faces in positive side cells and old split faces */
4021         for (e = 0, q = 0; e < supportSize; ++e) {
4022           PetscInt val;
4023 
4024           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4025           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4026         }
4027         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4028         /* Split new edge: Faces in negative side cells and new split faces */
4029         for (e = 0, q = 0; e < supportSize; ++e) {
4030           PetscInt val;
4031 
4032           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4033           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4034         }
4035         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4036       }
4037     }
4038   }
4039   /* Step 4: Setup split DM */
4040   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4041   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4042   /* Step 6: Set cones and supports for new points */
4043   for (dep = 0; dep <= depth; ++dep) {
4044     for (p = 0; p < numSplitPoints[dep]; ++p) {
4045       const PetscInt  oldp   = splitPoints[dep][p];
4046       const PetscInt  newp   = depthOffset[dep] + oldp;
4047       const PetscInt  splitp = pMaxNew[dep] + p;
4048       const PetscInt *cone, *support, *ornt;
4049       PetscInt        coneSize, supportSize, q, v, e, s;
4050 
4051       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4052       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4053       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4054       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4055       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4056       if (dep == depth-1) {
4057         const PetscInt  ccell = pMaxNew[depth] + p;
4058         const PetscInt *supportF;
4059 
4060         /* Split face:       copy in old face to new face to start */
4061         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4062         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4063         /* Split old face:   old vertices/edges in cone so no change */
4064         /* Split new face:   new vertices/edges in cone */
4065         for (q = 0; q < coneSize; ++q) {
4066           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4067 
4068           coneNew[2+q] = pMaxNew[dim-2] + v;
4069         }
4070         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4071         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4072         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4073         coneNew[0] = newp;
4074         coneNew[1] = splitp;
4075         for (q = 0; q < coneSize; ++q) {
4076           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4077         }
4078         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4079 
4080 
4081         for (s = 0; s < supportSize; ++s) {
4082           PetscInt val;
4083 
4084           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4085           if (val < 0) {
4086             /* Split old face:   Replace negative side cell with cohesive cell */
4087             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4088           } else {
4089             /* Split new face:   Replace positive side cell with cohesive cell */
4090             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4091           }
4092         }
4093       } else if (dep == 0) {
4094         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4095 
4096         /* Split old vertex: Edges in old split faces and new cohesive edge */
4097         for (e = 0, q = 0; e < supportSize; ++e) {
4098           PetscInt val;
4099 
4100           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4101           if ((val == 1) || (val == (shift + 1))) {
4102             supportNew[q++] = depthOffset[1] + support[e];
4103           }
4104         }
4105         supportNew[q] = cedge;
4106 
4107         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4108         /* Split new vertex: Edges in new split faces and new cohesive edge */
4109         for (e = 0, q = 0; e < supportSize; ++e) {
4110           PetscInt val, edge;
4111 
4112           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4113           if (val == 1) {
4114             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4115             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4116             supportNew[q++] = pMaxNew[1] + edge;
4117           } else if (val == -(shift + 1)) {
4118             supportNew[q++] = depthOffset[1] + support[e];
4119           }
4120         }
4121         supportNew[q] = cedge;
4122         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4123         /* Cohesive edge:    Old and new split vertex, punting on support */
4124         coneNew[0] = newp;
4125         coneNew[1] = splitp;
4126         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4127       } else if (dep == dim-2) {
4128         /* Split old edge:   old vertices in cone so no change */
4129         /* Split new edge:   new vertices in cone */
4130         for (q = 0; q < coneSize; ++q) {
4131           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4132 
4133           coneNew[q] = pMaxNew[dim-3] + v;
4134         }
4135         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4136         /* Split old edge: Faces in positive side cells and old split faces */
4137         for (e = 0, q = 0; e < supportSize; ++e) {
4138           PetscInt val;
4139 
4140           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4141           if ((val == dim-1) || (val == (shift + dim-1))) {
4142             supportNew[q++] = depthOffset[dim-1] + support[e];
4143           }
4144         }
4145         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4146         /* Split new edge: Faces in negative side cells and new split faces */
4147         for (e = 0, q = 0; e < supportSize; ++e) {
4148           PetscInt val, face;
4149 
4150           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4151           if (val == dim-1) {
4152             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4153             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4154             supportNew[q++] = pMaxNew[dim-1] + face;
4155           } else if (val == -(shift + dim-1)) {
4156             supportNew[q++] = depthOffset[dim-1] + support[e];
4157           }
4158         }
4159         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4160       }
4161     }
4162   }
4163   /* Step 6b: Replace split points in negative side cones */
4164   for (sp = 0; sp < numSP; ++sp) {
4165     PetscInt        dep = values[sp];
4166     IS              pIS;
4167     PetscInt        numPoints;
4168     const PetscInt *points;
4169 
4170     if (dep >= 0) continue;
4171     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4172     if (!pIS) continue;
4173     dep  = -dep - shift;
4174     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4175     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4176     for (p = 0; p < numPoints; ++p) {
4177       const PetscInt  oldp = points[p];
4178       const PetscInt  newp = depthOffset[dep] + oldp;
4179       const PetscInt *cone;
4180       PetscInt        coneSize, c;
4181       PetscBool       replaced = PETSC_FALSE;
4182 
4183       /* Negative edge: replace split vertex */
4184       /* Negative cell: replace split face */
4185       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4186       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4187       for (c = 0; c < coneSize; ++c) {
4188         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4189         PetscInt       csplitp, cp, val;
4190 
4191         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4192         if (val == dep-1) {
4193           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4194           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4195           csplitp  = pMaxNew[dep-1] + cp;
4196           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4197           replaced = PETSC_TRUE;
4198         }
4199       }
4200       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4201     }
4202     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4203     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4204   }
4205   /* Step 7: Stratify */
4206   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4207   /* Step 8: Coordinates */
4208   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4209   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4210   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4211   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4212   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4213     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4214     const PetscInt splitp = pMaxNew[0] + v;
4215     PetscInt       dof, off, soff, d;
4216 
4217     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4218     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4219     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4220     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4221   }
4222   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4223   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4224   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4225   /* Step 10: Labels */
4226   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4227   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4228   for (dep = 0; dep <= depth; ++dep) {
4229     for (p = 0; p < numSplitPoints[dep]; ++p) {
4230       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4231       const PetscInt splitp = pMaxNew[dep] + p;
4232       PetscInt       l;
4233 
4234       for (l = 0; l < numLabels; ++l) {
4235         DMLabel     mlabel;
4236         const char *lname;
4237         PetscInt    val;
4238 
4239         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4240         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4241         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4242         if (val >= 0) {
4243           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4244           if (dep == 0) {
4245             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4246             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4247           }
4248         }
4249       }
4250     }
4251   }
4252   for (sp = 0; sp < numSP; ++sp) {
4253     const PetscInt dep = values[sp];
4254 
4255     if ((dep < 0) || (dep > depth)) continue;
4256     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4257     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4258   }
4259   if (label) {
4260     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4261     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4262   }
4263   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4264   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4265   PetscFunctionReturn(0);
4266 }
4267 
4268 #undef __FUNCT__
4269 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4270 /*@C
4271   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4272 
4273   Collective on dm
4274 
4275   Input Parameters:
4276 + dm - The original DM
4277 - labelName - The label specifying the boundary faces (this could be auto-generated)
4278 
4279   Output Parameters:
4280 - dmSplit - The new DM
4281 
4282   Level: developer
4283 
4284 .seealso: DMCreate()
4285 */
4286 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4287 {
4288   DM             sdm;
4289   PetscInt       dim;
4290   PetscErrorCode ierr;
4291 
4292   PetscFunctionBegin;
4293   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4294   PetscValidPointer(dmSplit, 4);
4295   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &sdm);CHKERRQ(ierr);
4296   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4297   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4298   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4299   switch (dim) {
4300   case 2:
4301   case 3:
4302     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4303     break;
4304   default:
4305     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4306   }
4307   *dmSplit = sdm;
4308   PetscFunctionReturn(0);
4309 }
4310 
4311 #undef __FUNCT__
4312 #define __FUNCT__ "DMLabelCohesiveComplete"
4313 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4314 {
4315   IS              dimIS;
4316   const PetscInt *points;
4317   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4318   PetscErrorCode  ierr;
4319 
4320   PetscFunctionBegin;
4321   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4322   /* Cell orientation for face gives the side of the fault */
4323   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4324   if (!dimIS) PetscFunctionReturn(0);
4325   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4326   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4327   for (p = 0; p < numPoints; ++p) {
4328     const PetscInt *support;
4329     PetscInt        supportSize, s;
4330 
4331     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4332     if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4333     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4334     for (s = 0; s < supportSize; ++s) {
4335       const PetscInt *cone, *ornt;
4336       PetscInt        coneSize, c;
4337       PetscBool       pos = PETSC_TRUE;
4338 
4339       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4340       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4341       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4342       for (c = 0; c < coneSize; ++c) {
4343         if (cone[c] == points[p]) {
4344           if (ornt[c] >= 0) {
4345             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4346           } else {
4347             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4348             pos  = PETSC_FALSE;
4349           }
4350           break;
4351         }
4352       }
4353       if (c == coneSize) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4354       /* Put faces touching the fault in the label */
4355       for (c = 0; c < coneSize; ++c) {
4356         const PetscInt point = cone[c];
4357 
4358         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4359         if (val == -1) {
4360           PetscInt *closure = NULL;
4361           PetscInt  closureSize, cl;
4362 
4363           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4364           for (cl = 0; cl < closureSize*2; cl += 2) {
4365             const PetscInt clp = closure[cl];
4366 
4367             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4368             if ((val >= 0) && (val < dim-1)) {
4369               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4370               break;
4371             }
4372           }
4373           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4374         }
4375       }
4376     }
4377   }
4378   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4379   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4380   /* Search for other cells/faces/edges connected to the fault by a vertex */
4381   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4382   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4383   if (!dimIS) PetscFunctionReturn(0);
4384   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4385   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4386   for (p = 0; p < numPoints; ++p) {
4387     PetscInt *star = NULL;
4388     PetscInt  starSize, s;
4389     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4390 
4391     /* First mark cells connected to the fault */
4392     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4393     while (again) {
4394       if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4395       again = 0;
4396       for (s = 0; s < starSize*2; s += 2) {
4397         const PetscInt  point = star[s];
4398         const PetscInt *cone;
4399         PetscInt        coneSize, c;
4400 
4401         if ((point < cStart) || (point >= cEnd)) continue;
4402         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4403         if (val != -1) continue;
4404         again = 2;
4405         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4406         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4407         for (c = 0; c < coneSize; ++c) {
4408           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4409           if (val != -1) {
4410             if (abs(val) < shift) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4411             if (val > 0) {
4412               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4413             } else {
4414               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4415             }
4416             again = 1;
4417             break;
4418           }
4419         }
4420       }
4421     }
4422     /* Classify the rest by cell membership */
4423     for (s = 0; s < starSize*2; s += 2) {
4424       const PetscInt point = star[s];
4425 
4426       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4427       if (val == -1) {
4428         PetscInt  *sstar = NULL;
4429         PetscInt   sstarSize, ss;
4430         PetscBool  marked = PETSC_FALSE;
4431 
4432         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4433         for (ss = 0; ss < sstarSize*2; ss += 2) {
4434           const PetscInt spoint = sstar[ss];
4435 
4436           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4437           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4438           if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4439           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4440           if (val > 0) {
4441             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4442           } else {
4443             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4444           }
4445           marked = PETSC_TRUE;
4446           break;
4447         }
4448         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4449         if (!marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
4450       }
4451     }
4452     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4453   }
4454   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4455   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4456   PetscFunctionReturn(0);
4457 }
4458 
4459 #undef __FUNCT__
4460 #define __FUNCT__ "DMPlexInterpolate_2D"
4461 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4462 {
4463   DM             idm;
4464   DM_Plex       *mesh;
4465   PetscHashIJ    edgeTable;
4466   PetscInt      *off;
4467   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4468   PetscInt       numEdges, firstEdge, edge, e;
4469   PetscErrorCode ierr;
4470 
4471   PetscFunctionBegin;
4472   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4473   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4474   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4475   numCells    = cEnd - cStart;
4476   numVertices = vEnd - vStart;
4477   firstEdge   = numCells + numVertices;
4478   numEdges    = 0;
4479   /* Count edges using algorithm from CreateNeighborCSR */
4480   ierr = DMPlexCreateNeighborCSR(dm, NULL, &off, NULL);CHKERRQ(ierr);
4481   if (off) {
4482     PetscInt numCorners = 0;
4483 
4484     numEdges = off[numCells]/2;
4485 #if 0
4486     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4487     numEdges += 3*numCells - off[numCells];
4488 #else
4489     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4490     for (c = cStart; c < cEnd; ++c) {
4491       PetscInt coneSize;
4492 
4493       ierr        = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4494       numCorners += coneSize;
4495     }
4496     numEdges += numCorners - off[numCells];
4497 #endif
4498   }
4499 #if 0
4500   /* Check Euler characteristic V - E + F = 1 */
4501   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4502 #endif
4503   /* Create interpolated mesh */
4504   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &idm);CHKERRQ(ierr);
4505   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4506   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4507   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4508   for (c = 0; c < numCells; ++c) {
4509     PetscInt numCorners;
4510 
4511     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4512     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4513   }
4514   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4515     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4516   }
4517   ierr = DMSetUp(idm);CHKERRQ(ierr);
4518   /* Get edge cones from subsets of cell vertices */
4519   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4520   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4521 
4522   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4523     const PetscInt *cellFaces;
4524     PetscInt        numCellFaces, faceSize, cf;
4525 
4526     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4527     if (faceSize != 2) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4528     for (cf = 0; cf < numCellFaces; ++cf) {
4529 #if 1
4530       PetscHashIJKey key;
4531 
4532       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4533       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4534       ierr  = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4535       if (e < 0) {
4536         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4537         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4538         e    = edge++;
4539       }
4540 #else
4541       PetscBool found = PETSC_FALSE;
4542 
4543       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4544       for (e = firstEdge; e < edge; ++e) {
4545         const PetscInt *cone;
4546 
4547         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4548         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4549             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4550           found = PETSC_TRUE;
4551           break;
4552         }
4553       }
4554       if (!found) {
4555         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4556         ++edge;
4557       }
4558 #endif
4559       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4560     }
4561   }
4562   if (edge != firstEdge+numEdges) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4563   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4564   ierr = PetscFree(off);CHKERRQ(ierr);
4565   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4566   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4567   mesh = (DM_Plex*) (idm)->data;
4568   /* Orient edges */
4569   for (c = 0; c < numCells; ++c) {
4570     const PetscInt *cone = NULL, *cellFaces;
4571     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4572 
4573     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4574     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4575     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4576     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4577     if (coneSize != numCellFaces) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4578     for (cf = 0; cf < numCellFaces; ++cf) {
4579       const PetscInt *econe = NULL;
4580       PetscInt        esize;
4581 
4582       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4583       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4584       if (esize != 2) SETERRQ2(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4585       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4586         /* Correctly oriented */
4587         mesh->coneOrientations[coff+cf] = 0;
4588       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4589         /* Start at index 1, and reverse orientation */
4590         mesh->coneOrientations[coff+cf] = -(1+1);
4591       }
4592     }
4593   }
4594   *dmInt = idm;
4595   PetscFunctionReturn(0);
4596 }
4597 
4598 #undef __FUNCT__
4599 #define __FUNCT__ "DMPlexInterpolate_3D"
4600 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4601 {
4602   DM             idm, fdm;
4603   DM_Plex       *mesh;
4604   PetscInt      *off;
4605   const PetscInt numCorners = 4;
4606   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4607   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4608   PetscErrorCode ierr;
4609 
4610   PetscFunctionBegin;
4611   {
4612     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4613     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4614     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4615   }
4616   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4617   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4618   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4619   numCells    = cEnd - cStart;
4620   numVertices = vEnd - vStart;
4621   firstFace   = numCells + numVertices;
4622   numFaces    = 0;
4623   /* Count faces using algorithm from CreateNeighborCSR */
4624   ierr = DMPlexCreateNeighborCSR(dm, NULL, &off, NULL);CHKERRQ(ierr);
4625   if (off) {
4626     numFaces = off[numCells]/2;
4627     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4628     numFaces += 4*numCells - off[numCells];
4629   }
4630   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4631   firstEdge = firstFace + numFaces;
4632   numEdges  = numVertices + numFaces - numCells - 1;
4633   /* Create interpolated mesh */
4634   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &idm);CHKERRQ(ierr);
4635   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4636   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4637   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4638   for (c = 0; c < numCells; ++c) {
4639     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4640   }
4641   for (f = firstFace; f < firstFace+numFaces; ++f) {
4642     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4643   }
4644   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4645     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4646   }
4647   ierr = DMSetUp(idm);CHKERRQ(ierr);
4648   /* Get face cones from subsets of cell vertices */
4649   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &fdm);CHKERRQ(ierr);
4650   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4651   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4652   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4653   for (f = firstFace; f < firstFace+numFaces; ++f) {
4654     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4655   }
4656   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4657   for (c = 0, face = firstFace; c < numCells; ++c) {
4658     const PetscInt *cellFaces;
4659     PetscInt        numCellFaces, faceSize, cf;
4660 
4661     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4662     if (faceSize != 3) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4663     for (cf = 0; cf < numCellFaces; ++cf) {
4664       PetscBool found = PETSC_FALSE;
4665 
4666       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4667       for (f = firstFace; f < face; ++f) {
4668         const PetscInt *cone = NULL;
4669 
4670         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4671         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4672             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4673             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4674             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4675             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4676             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4677           found = PETSC_TRUE;
4678           break;
4679         }
4680       }
4681       if (!found) {
4682         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4683         /* Save the vertices for orientation calculation */
4684         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4685         ++face;
4686       }
4687       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4688     }
4689   }
4690   if (face != firstFace+numFaces) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4691   /* Get edge cones from subsets of face vertices */
4692   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4693     const PetscInt *cellFaces;
4694     PetscInt        numCellFaces, faceSize, cf;
4695 
4696     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4697     if (faceSize != 2) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4698     for (cf = 0; cf < numCellFaces; ++cf) {
4699       PetscBool found = PETSC_FALSE;
4700 
4701       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4702       for (e = firstEdge; e < edge; ++e) {
4703         const PetscInt *cone = NULL;
4704 
4705         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4706         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4707             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4708           found = PETSC_TRUE;
4709           break;
4710         }
4711       }
4712       if (!found) {
4713         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4714         ++edge;
4715       }
4716       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4717     }
4718   }
4719   if (edge != firstEdge+numEdges) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4720   ierr = PetscFree(off);CHKERRQ(ierr);
4721   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4722   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4723   mesh = (DM_Plex*) (idm)->data;
4724   /* Orient edges */
4725   for (f = firstFace; f < firstFace+numFaces; ++f) {
4726     const PetscInt *cone, *cellFaces;
4727     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4728 
4729     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4730     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4731     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4732     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4733     if (coneSize != numCellFaces) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4734     for (cf = 0; cf < numCellFaces; ++cf) {
4735       const PetscInt *econe;
4736       PetscInt        esize;
4737 
4738       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4739       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4740       if (esize != 2) SETERRQ2(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4741       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4742         /* Correctly oriented */
4743         mesh->coneOrientations[coff+cf] = 0;
4744       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4745         /* Start at index 1, and reverse orientation */
4746         mesh->coneOrientations[coff+cf] = -(1+1);
4747       }
4748     }
4749   }
4750   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4751   /* Orient faces */
4752   for (c = 0; c < numCells; ++c) {
4753     const PetscInt *cone, *cellFaces;
4754     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4755 
4756     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4757     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4758     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4759     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4760     if (coneSize != numCellFaces) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4761     for (cf = 0; cf < numCellFaces; ++cf) {
4762       PetscInt *origClosure = NULL, *closure;
4763       PetscInt closureSize, i;
4764 
4765       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4766       if (closureSize != 7) SETERRQ2(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4767       for (i = 4; i < 7; ++i) {
4768         if ((origClosure[i*2] < vStart) || (origClosure[i*2] >= vEnd)) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid closure point %D should be a vertex in [%D, %D)", origClosure[i*2], vStart, vEnd);
4769       }
4770       closure = &origClosure[4*2];
4771       /* Remember that this is the orientation for edges, not vertices */
4772       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4773         /* Correctly oriented */
4774         mesh->coneOrientations[coff+cf] = 0;
4775       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4776         /* Shifted by 1 */
4777         mesh->coneOrientations[coff+cf] = 1;
4778       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4779         /* Shifted by 2 */
4780         mesh->coneOrientations[coff+cf] = 2;
4781       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4782         /* Start at edge 1, and reverse orientation */
4783         mesh->coneOrientations[coff+cf] = -(1+1);
4784       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4785         /* Start at index 0, and reverse orientation */
4786         mesh->coneOrientations[coff+cf] = -(0+1);
4787       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4788         /* Start at index 2, and reverse orientation */
4789         mesh->coneOrientations[coff+cf] = -(2+1);
4790       } else SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Face %D did not match local face %D in cell %D for any orientation", cone[cf], cf, c);
4791       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4792     }
4793   }
4794   {
4795     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4796     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4797     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4798   }
4799   *dmInt = idm;
4800   PetscFunctionReturn(0);
4801 }
4802 
4803 #undef __FUNCT__
4804 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4805 /*
4806   This takes as input the common mesh generator output, a list of the vertices for each cell
4807 */
4808 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4809 {
4810   PetscInt      *cone, c, p;
4811   PetscErrorCode ierr;
4812 
4813   PetscFunctionBegin;
4814   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4815   for (c = 0; c < numCells; ++c) {
4816     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4817   }
4818   ierr = DMSetUp(dm);CHKERRQ(ierr);
4819   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4820   for (c = 0; c < numCells; ++c) {
4821     for (p = 0; p < numCorners; ++p) {
4822       cone[p] = cells[c*numCorners+p]+numCells;
4823     }
4824     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4825   }
4826   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4827   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4828   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4829   PetscFunctionReturn(0);
4830 }
4831 
4832 #undef __FUNCT__
4833 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4834 /*
4835   This takes as input the coordinates for each vertex
4836 */
4837 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4838 {
4839   PetscSection   coordSection;
4840   Vec            coordinates;
4841   PetscScalar   *coords;
4842   PetscInt       coordSize, v, d;
4843   PetscErrorCode ierr;
4844 
4845   PetscFunctionBegin;
4846   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4847   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4848   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4849   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4850   for (v = numCells; v < numCells+numVertices; ++v) {
4851     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4852     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4853   }
4854   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4855   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4856   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4857   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4858   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4859   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4860   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4861   for (v = 0; v < numVertices; ++v) {
4862     for (d = 0; d < spaceDim; ++d) {
4863       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4864     }
4865   }
4866   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4867   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4868   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4869   PetscFunctionReturn(0);
4870 }
4871 
4872 #undef __FUNCT__
4873 #define __FUNCT__ "DMPlexCreateFromCellList"
4874 /*
4875   This takes as input the common mesh generator output, a list of the vertices for each cell
4876 */
4877 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4878 {
4879   PetscErrorCode ierr;
4880 
4881   PetscFunctionBegin;
4882   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4883   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4884   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4885   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4886   if (interpolate) {
4887     DM idm;
4888 
4889     switch (dim) {
4890     case 2:
4891       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4892     case 3:
4893       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4894     default:
4895       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4896     }
4897     ierr = DMDestroy(dm);CHKERRQ(ierr);
4898     *dm  = idm;
4899   }
4900   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4901   PetscFunctionReturn(0);
4902 }
4903 
4904 #if defined(PETSC_HAVE_TRIANGLE)
4905 #include <triangle.h>
4906 
4907 #undef __FUNCT__
4908 #define __FUNCT__ "InitInput_Triangle"
4909 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4910 {
4911   PetscFunctionBegin;
4912   inputCtx->numberofpoints             = 0;
4913   inputCtx->numberofpointattributes    = 0;
4914   inputCtx->pointlist                  = NULL;
4915   inputCtx->pointattributelist         = NULL;
4916   inputCtx->pointmarkerlist            = NULL;
4917   inputCtx->numberofsegments           = 0;
4918   inputCtx->segmentlist                = NULL;
4919   inputCtx->segmentmarkerlist          = NULL;
4920   inputCtx->numberoftriangleattributes = 0;
4921   inputCtx->trianglelist               = NULL;
4922   inputCtx->numberofholes              = 0;
4923   inputCtx->holelist                   = NULL;
4924   inputCtx->numberofregions            = 0;
4925   inputCtx->regionlist                 = NULL;
4926   PetscFunctionReturn(0);
4927 }
4928 
4929 #undef __FUNCT__
4930 #define __FUNCT__ "InitOutput_Triangle"
4931 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4932 {
4933   PetscFunctionBegin;
4934   outputCtx->numberofpoints        = 0;
4935   outputCtx->pointlist             = NULL;
4936   outputCtx->pointattributelist    = NULL;
4937   outputCtx->pointmarkerlist       = NULL;
4938   outputCtx->numberoftriangles     = 0;
4939   outputCtx->trianglelist          = NULL;
4940   outputCtx->triangleattributelist = NULL;
4941   outputCtx->neighborlist          = NULL;
4942   outputCtx->segmentlist           = NULL;
4943   outputCtx->segmentmarkerlist     = NULL;
4944   outputCtx->numberofedges         = 0;
4945   outputCtx->edgelist              = NULL;
4946   outputCtx->edgemarkerlist        = NULL;
4947   PetscFunctionReturn(0);
4948 }
4949 
4950 #undef __FUNCT__
4951 #define __FUNCT__ "FiniOutput_Triangle"
4952 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4953 {
4954   PetscFunctionBegin;
4955   free(outputCtx->pointmarkerlist);
4956   free(outputCtx->edgelist);
4957   free(outputCtx->edgemarkerlist);
4958   free(outputCtx->trianglelist);
4959   free(outputCtx->neighborlist);
4960   PetscFunctionReturn(0);
4961 }
4962 
4963 #undef __FUNCT__
4964 #define __FUNCT__ "DMPlexGenerate_Triangle"
4965 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4966 {
4967   MPI_Comm             comm;
4968   PetscInt             dim              = 2;
4969   const PetscBool      createConvexHull = PETSC_FALSE;
4970   const PetscBool      constrained      = PETSC_FALSE;
4971   struct triangulateio in;
4972   struct triangulateio out;
4973   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4974   PetscMPIInt          rank;
4975   PetscErrorCode       ierr;
4976 
4977   PetscFunctionBegin;
4978   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4979   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4980   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4981   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4982   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4983 
4984   in.numberofpoints = vEnd - vStart;
4985   if (in.numberofpoints > 0) {
4986     PetscSection coordSection;
4987     Vec          coordinates;
4988     PetscScalar *array;
4989 
4990     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4991     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4992     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4993     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4994     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4995     for (v = vStart; v < vEnd; ++v) {
4996       const PetscInt idx = v - vStart;
4997       PetscInt       off, d;
4998 
4999       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5000       for (d = 0; d < dim; ++d) {
5001         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5002       }
5003       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5004     }
5005     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5006   }
5007   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
5008   in.numberofsegments = eEnd - eStart;
5009   if (in.numberofsegments > 0) {
5010     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
5011     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
5012     for (e = eStart; e < eEnd; ++e) {
5013       const PetscInt  idx = e - eStart;
5014       const PetscInt *cone;
5015 
5016       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
5017 
5018       in.segmentlist[idx*2+0] = cone[0] - vStart;
5019       in.segmentlist[idx*2+1] = cone[1] - vStart;
5020 
5021       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5022     }
5023   }
5024 #if 0 /* Do not currently support holes */
5025   PetscReal *holeCoords;
5026   PetscInt   h, d;
5027 
5028   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5029   if (in.numberofholes > 0) {
5030     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5031     for (h = 0; h < in.numberofholes; ++h) {
5032       for (d = 0; d < dim; ++d) {
5033         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5034       }
5035     }
5036   }
5037 #endif
5038   if (!rank) {
5039     char args[32];
5040 
5041     /* Take away 'Q' for verbose output */
5042     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5043     if (createConvexHull) {
5044       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5045     }
5046     if (constrained) {
5047       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5048     }
5049     triangulate(args, &in, &out, NULL);
5050   }
5051   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5052   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5053   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5054   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5055   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5056 
5057   {
5058     const PetscInt numCorners  = 3;
5059     const PetscInt numCells    = out.numberoftriangles;
5060     const PetscInt numVertices = out.numberofpoints;
5061     const int     *cells      = out.trianglelist;
5062     const double  *meshCoords = out.pointlist;
5063 
5064     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5065     /* Set labels */
5066     for (v = 0; v < numVertices; ++v) {
5067       if (out.pointmarkerlist[v]) {
5068         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5069       }
5070     }
5071     if (interpolate) {
5072       for (e = 0; e < out.numberofedges; e++) {
5073         if (out.edgemarkerlist[e]) {
5074           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5075           const PetscInt *edges;
5076           PetscInt        numEdges;
5077 
5078           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5079           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5080           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5081           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5082         }
5083       }
5084     }
5085     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5086   }
5087 #if 0 /* Do not currently support holes */
5088   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5089 #endif
5090   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5091   PetscFunctionReturn(0);
5092 }
5093 
5094 #undef __FUNCT__
5095 #define __FUNCT__ "DMPlexRefine_Triangle"
5096 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5097 {
5098   MPI_Comm             comm;
5099   PetscInt             dim  = 2;
5100   struct triangulateio in;
5101   struct triangulateio out;
5102   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5103   PetscMPIInt          rank;
5104   PetscErrorCode       ierr;
5105 
5106   PetscFunctionBegin;
5107   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5108   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5109   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5110   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5111   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5112   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5113   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5114 
5115   in.numberofpoints = vEnd - vStart;
5116   if (in.numberofpoints > 0) {
5117     PetscSection coordSection;
5118     Vec          coordinates;
5119     PetscScalar *array;
5120 
5121     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5122     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5123     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5124     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5125     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5126     for (v = vStart; v < vEnd; ++v) {
5127       const PetscInt idx = v - vStart;
5128       PetscInt       off, d;
5129 
5130       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5131       for (d = 0; d < dim; ++d) {
5132         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5133       }
5134       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5135     }
5136     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5137   }
5138   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5139 
5140   in.numberofcorners   = 3;
5141   in.numberoftriangles = cEnd - cStart;
5142 
5143   in.trianglearealist  = (double*) maxVolumes;
5144   if (in.numberoftriangles > 0) {
5145     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5146     for (c = cStart; c < cEnd; ++c) {
5147       const PetscInt idx      = c - cStart;
5148       PetscInt      *closure = NULL;
5149       PetscInt       closureSize;
5150 
5151       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5152       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5153       for (v = 0; v < 3; ++v) {
5154         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5155       }
5156       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5157     }
5158   }
5159   /* TODO: Segment markers are missing on input */
5160 #if 0 /* Do not currently support holes */
5161   PetscReal *holeCoords;
5162   PetscInt   h, d;
5163 
5164   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5165   if (in.numberofholes > 0) {
5166     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5167     for (h = 0; h < in.numberofholes; ++h) {
5168       for (d = 0; d < dim; ++d) {
5169         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5170       }
5171     }
5172   }
5173 #endif
5174   if (!rank) {
5175     char args[32];
5176 
5177     /* Take away 'Q' for verbose output */
5178     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5179     triangulate(args, &in, &out, NULL);
5180   }
5181   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5182   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5183   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5184   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5185   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5186 
5187   {
5188     const PetscInt numCorners  = 3;
5189     const PetscInt numCells    = out.numberoftriangles;
5190     const PetscInt numVertices = out.numberofpoints;
5191     const int     *cells      = out.trianglelist;
5192     const double  *meshCoords = out.pointlist;
5193     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5194 
5195     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5196     /* Set labels */
5197     for (v = 0; v < numVertices; ++v) {
5198       if (out.pointmarkerlist[v]) {
5199         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5200       }
5201     }
5202     if (interpolate) {
5203       PetscInt e;
5204 
5205       for (e = 0; e < out.numberofedges; e++) {
5206         if (out.edgemarkerlist[e]) {
5207           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5208           const PetscInt *edges;
5209           PetscInt        numEdges;
5210 
5211           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5212           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5213           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5214           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5215         }
5216       }
5217     }
5218     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5219   }
5220 #if 0 /* Do not currently support holes */
5221   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5222 #endif
5223   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5224   PetscFunctionReturn(0);
5225 }
5226 #endif
5227 
5228 #if defined(PETSC_HAVE_TETGEN)
5229 #include <tetgen.h>
5230 #undef __FUNCT__
5231 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5232 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5233 {
5234   MPI_Comm       comm;
5235   const PetscInt dim  = 3;
5236   ::tetgenio     in;
5237   ::tetgenio     out;
5238   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5239   PetscMPIInt    rank;
5240   PetscErrorCode ierr;
5241 
5242   PetscFunctionBegin;
5243   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5244   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5245   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5246   in.numberofpoints = vEnd - vStart;
5247   if (in.numberofpoints > 0) {
5248     PetscSection coordSection;
5249     Vec          coordinates;
5250     PetscScalar *array;
5251 
5252     in.pointlist       = new double[in.numberofpoints*dim];
5253     in.pointmarkerlist = new int[in.numberofpoints];
5254 
5255     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5256     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5257     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5258     for (v = vStart; v < vEnd; ++v) {
5259       const PetscInt idx = v - vStart;
5260       PetscInt       off, d;
5261 
5262       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5263       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5264       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5265     }
5266     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5267   }
5268   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5269 
5270   in.numberoffacets = fEnd - fStart;
5271   if (in.numberoffacets > 0) {
5272     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5273     in.facetmarkerlist = new int[in.numberoffacets];
5274     for (f = fStart; f < fEnd; ++f) {
5275       const PetscInt idx     = f - fStart;
5276       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
5277 
5278       in.facetlist[idx].numberofpolygons = 1;
5279       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5280       in.facetlist[idx].numberofholes    = 0;
5281       in.facetlist[idx].holelist         = NULL;
5282 
5283       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5284       for (p = 0; p < numPoints*2; p += 2) {
5285         const PetscInt point = points[p];
5286         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5287       }
5288 
5289       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5290       poly->numberofvertices = numVertices;
5291       poly->vertexlist       = new int[poly->numberofvertices];
5292       for (v = 0; v < numVertices; ++v) {
5293         const PetscInt vIdx = points[v] - vStart;
5294         poly->vertexlist[v] = vIdx;
5295       }
5296       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5297       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5298     }
5299   }
5300   if (!rank) {
5301     char args[32];
5302 
5303     /* Take away 'Q' for verbose output */
5304     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5305     ::tetrahedralize(args, &in, &out);
5306   }
5307   {
5308     const PetscInt numCorners  = 4;
5309     const PetscInt numCells    = out.numberoftetrahedra;
5310     const PetscInt numVertices = out.numberofpoints;
5311     const int     *cells      = out.tetrahedronlist;
5312     const double  *meshCoords = out.pointlist;
5313 
5314     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5315     /* Set labels */
5316     for (v = 0; v < numVertices; ++v) {
5317       if (out.pointmarkerlist[v]) {
5318         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5319       }
5320     }
5321     if (interpolate) {
5322       PetscInt e;
5323 
5324       for (e = 0; e < out.numberofedges; e++) {
5325         if (out.edgemarkerlist[e]) {
5326           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5327           const PetscInt *edges;
5328           PetscInt        numEdges;
5329 
5330           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5331           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5332           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5333           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5334         }
5335       }
5336       for (f = 0; f < out.numberoftrifaces; f++) {
5337         if (out.trifacemarkerlist[f]) {
5338           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5339           const PetscInt *faces;
5340           PetscInt        numFaces;
5341 
5342           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5343           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5344           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5345           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5346         }
5347       }
5348     }
5349     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5350   }
5351   PetscFunctionReturn(0);
5352 }
5353 
5354 #undef __FUNCT__
5355 #define __FUNCT__ "DMPlexRefine_Tetgen"
5356 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5357 {
5358   MPI_Comm       comm;
5359   const PetscInt dim  = 3;
5360   ::tetgenio     in;
5361   ::tetgenio     out;
5362   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5363   PetscMPIInt    rank;
5364   PetscErrorCode ierr;
5365 
5366   PetscFunctionBegin;
5367   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5368   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5369   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5370   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5371   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5372 
5373   in.numberofpoints = vEnd - vStart;
5374   if (in.numberofpoints > 0) {
5375     PetscSection coordSection;
5376     Vec          coordinates;
5377     PetscScalar *array;
5378 
5379     in.pointlist       = new double[in.numberofpoints*dim];
5380     in.pointmarkerlist = new int[in.numberofpoints];
5381 
5382     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5383     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5384     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5385     for (v = vStart; v < vEnd; ++v) {
5386       const PetscInt idx = v - vStart;
5387       PetscInt       off, d;
5388 
5389       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5390       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5391       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5392     }
5393     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5394   }
5395   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5396 
5397   in.numberofcorners       = 4;
5398   in.numberoftetrahedra    = cEnd - cStart;
5399   in.tetrahedronvolumelist = (double*) maxVolumes;
5400   if (in.numberoftetrahedra > 0) {
5401     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5402     for (c = cStart; c < cEnd; ++c) {
5403       const PetscInt idx      = c - cStart;
5404       PetscInt      *closure = NULL;
5405       PetscInt       closureSize;
5406 
5407       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5408       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5409       for (v = 0; v < 4; ++v) {
5410         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5411       }
5412       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5413     }
5414   }
5415   /* TODO: Put in boundary faces with markers */
5416   if (!rank) {
5417     char args[32];
5418 
5419     /* Take away 'Q' for verbose output */
5420     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5421     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5422     ::tetrahedralize(args, &in, &out);
5423   }
5424   in.tetrahedronvolumelist = NULL;
5425 
5426   {
5427     const PetscInt numCorners  = 4;
5428     const PetscInt numCells    = out.numberoftetrahedra;
5429     const PetscInt numVertices = out.numberofpoints;
5430     const int     *cells      = out.tetrahedronlist;
5431     const double  *meshCoords = out.pointlist;
5432     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5433 
5434     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5435     /* Set labels */
5436     for (v = 0; v < numVertices; ++v) {
5437       if (out.pointmarkerlist[v]) {
5438         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5439       }
5440     }
5441     if (interpolate) {
5442       PetscInt e, f;
5443 
5444       for (e = 0; e < out.numberofedges; e++) {
5445         if (out.edgemarkerlist[e]) {
5446           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5447           const PetscInt *edges;
5448           PetscInt        numEdges;
5449 
5450           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5451           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5452           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5453           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5454         }
5455       }
5456       for (f = 0; f < out.numberoftrifaces; f++) {
5457         if (out.trifacemarkerlist[f]) {
5458           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5459           const PetscInt *faces;
5460           PetscInt        numFaces;
5461 
5462           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5463           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5464           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5465           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5466         }
5467       }
5468     }
5469     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5470   }
5471   PetscFunctionReturn(0);
5472 }
5473 #endif
5474 
5475 #if defined(PETSC_HAVE_CTETGEN)
5476 #include "ctetgen.h"
5477 
5478 #undef __FUNCT__
5479 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5480 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5481 {
5482   MPI_Comm       comm;
5483   const PetscInt dim  = 3;
5484   PLC           *in, *out;
5485   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5486   PetscMPIInt    rank;
5487   PetscErrorCode ierr;
5488 
5489   PetscFunctionBegin;
5490   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5491   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5492   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5493   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5494   ierr = PLCCreate(&in);CHKERRQ(ierr);
5495   ierr = PLCCreate(&out);CHKERRQ(ierr);
5496 
5497   in->numberofpoints = vEnd - vStart;
5498   if (in->numberofpoints > 0) {
5499     PetscSection coordSection;
5500     Vec          coordinates;
5501     PetscScalar *array;
5502 
5503     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5504     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5505     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5506     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5507     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5508     for (v = vStart; v < vEnd; ++v) {
5509       const PetscInt idx = v - vStart;
5510       PetscInt       off, d, m;
5511 
5512       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5513       for (d = 0; d < dim; ++d) {
5514         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5515       }
5516       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5517 
5518       in->pointmarkerlist[idx] = (int) m;
5519     }
5520     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5521   }
5522   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5523 
5524   in->numberoffacets = fEnd - fStart;
5525   if (in->numberoffacets > 0) {
5526     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5527     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5528     for (f = fStart; f < fEnd; ++f) {
5529       const PetscInt idx     = f - fStart;
5530       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5531       polygon       *poly;
5532 
5533       in->facetlist[idx].numberofpolygons = 1;
5534 
5535       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5536 
5537       in->facetlist[idx].numberofholes    = 0;
5538       in->facetlist[idx].holelist         = NULL;
5539 
5540       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5541       for (p = 0; p < numPoints*2; p += 2) {
5542         const PetscInt point = points[p];
5543         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5544       }
5545 
5546       poly                   = in->facetlist[idx].polygonlist;
5547       poly->numberofvertices = numVertices;
5548       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5549       for (v = 0; v < numVertices; ++v) {
5550         const PetscInt vIdx = points[v] - vStart;
5551         poly->vertexlist[v] = vIdx;
5552       }
5553       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5554       in->facetmarkerlist[idx] = (int) m;
5555       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5556     }
5557   }
5558   if (!rank) {
5559     TetGenOpts t;
5560 
5561     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5562     t.in        = boundary; /* Should go away */
5563     t.plc       = 1;
5564     t.quality   = 1;
5565     t.edgesout  = 1;
5566     t.zeroindex = 1;
5567     t.quiet     = 1;
5568     t.verbose   = verbose;
5569     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5570     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5571   }
5572   {
5573     const PetscInt numCorners  = 4;
5574     const PetscInt numCells    = out->numberoftetrahedra;
5575     const PetscInt numVertices = out->numberofpoints;
5576     const int     *cells      = out->tetrahedronlist;
5577     const double  *meshCoords = out->pointlist;
5578 
5579     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5580     /* Set labels */
5581     for (v = 0; v < numVertices; ++v) {
5582       if (out->pointmarkerlist[v]) {
5583         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5584       }
5585     }
5586     if (interpolate) {
5587       PetscInt e;
5588 
5589       for (e = 0; e < out->numberofedges; e++) {
5590         if (out->edgemarkerlist[e]) {
5591           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5592           const PetscInt *edges;
5593           PetscInt        numEdges;
5594 
5595           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5596           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5597           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5598           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5599         }
5600       }
5601       for (f = 0; f < out->numberoftrifaces; f++) {
5602         if (out->trifacemarkerlist[f]) {
5603           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5604           const PetscInt *faces;
5605           PetscInt        numFaces;
5606 
5607           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5608           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5609           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5610           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5611         }
5612       }
5613     }
5614     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5615   }
5616 
5617   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5618   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5619   PetscFunctionReturn(0);
5620 }
5621 
5622 #undef __FUNCT__
5623 #define __FUNCT__ "DMPlexRefine_CTetgen"
5624 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5625 {
5626   MPI_Comm       comm;
5627   const PetscInt dim  = 3;
5628   PLC           *in, *out;
5629   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5630   PetscMPIInt    rank;
5631   PetscErrorCode ierr;
5632 
5633   PetscFunctionBegin;
5634   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5635   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5636   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5637   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5638   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5639   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5640   ierr = PLCCreate(&in);CHKERRQ(ierr);
5641   ierr = PLCCreate(&out);CHKERRQ(ierr);
5642 
5643   in->numberofpoints = vEnd - vStart;
5644   if (in->numberofpoints > 0) {
5645     PetscSection coordSection;
5646     Vec          coordinates;
5647     PetscScalar *array;
5648 
5649     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5650     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5651     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5652     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5653     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5654     for (v = vStart; v < vEnd; ++v) {
5655       const PetscInt idx = v - vStart;
5656       PetscInt       off, d, m;
5657 
5658       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5659       for (d = 0; d < dim; ++d) {
5660         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5661       }
5662       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5663 
5664       in->pointmarkerlist[idx] = (int) m;
5665     }
5666     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5667   }
5668   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5669 
5670   in->numberofcorners       = 4;
5671   in->numberoftetrahedra    = cEnd - cStart;
5672   in->tetrahedronvolumelist = maxVolumes;
5673   if (in->numberoftetrahedra > 0) {
5674     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5675     for (c = cStart; c < cEnd; ++c) {
5676       const PetscInt idx      = c - cStart;
5677       PetscInt      *closure = NULL;
5678       PetscInt       closureSize;
5679 
5680       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5681       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5682       for (v = 0; v < 4; ++v) {
5683         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5684       }
5685       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5686     }
5687   }
5688   if (!rank) {
5689     TetGenOpts t;
5690 
5691     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5692 
5693     t.in        = dm; /* Should go away */
5694     t.refine    = 1;
5695     t.varvolume = 1;
5696     t.quality   = 1;
5697     t.edgesout  = 1;
5698     t.zeroindex = 1;
5699     t.quiet     = 1;
5700     t.verbose   = verbose; /* Change this */
5701 
5702     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5703     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5704   }
5705   {
5706     const PetscInt numCorners  = 4;
5707     const PetscInt numCells    = out->numberoftetrahedra;
5708     const PetscInt numVertices = out->numberofpoints;
5709     const int     *cells       = out->tetrahedronlist;
5710     const double  *meshCoords  = out->pointlist;
5711     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5712 
5713     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5714     /* Set labels */
5715     for (v = 0; v < numVertices; ++v) {
5716       if (out->pointmarkerlist[v]) {
5717         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5718       }
5719     }
5720     if (interpolate) {
5721       PetscInt e, f;
5722 
5723       for (e = 0; e < out->numberofedges; e++) {
5724         if (out->edgemarkerlist[e]) {
5725           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5726           const PetscInt *edges;
5727           PetscInt        numEdges;
5728 
5729           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5730           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5731           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5732           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5733         }
5734       }
5735       for (f = 0; f < out->numberoftrifaces; f++) {
5736         if (out->trifacemarkerlist[f]) {
5737           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5738           const PetscInt *faces;
5739           PetscInt        numFaces;
5740 
5741           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5742           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5743           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5744           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5745         }
5746       }
5747     }
5748     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5749   }
5750   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5751   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5752   PetscFunctionReturn(0);
5753 }
5754 #endif
5755 
5756 #undef __FUNCT__
5757 #define __FUNCT__ "DMPlexGenerate"
5758 /*@C
5759   DMPlexGenerate - Generates a mesh.
5760 
5761   Not Collective
5762 
5763   Input Parameters:
5764 + boundary - The DMPlex boundary object
5765 . name - The mesh generation package name
5766 - interpolate - Flag to create intermediate mesh elements
5767 
5768   Output Parameter:
5769 . mesh - The DMPlex object
5770 
5771   Level: intermediate
5772 
5773 .keywords: mesh, elements
5774 .seealso: DMPlexCreate(), DMRefine()
5775 @*/
5776 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5777 {
5778   PetscInt       dim;
5779   char           genname[1024];
5780   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5781   PetscErrorCode ierr;
5782 
5783   PetscFunctionBegin;
5784   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5785   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5786   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5787   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5788   if (flg) name = genname;
5789   if (name) {
5790     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5791     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5792     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5793   }
5794   switch (dim) {
5795   case 1:
5796     if (!name || isTriangle) {
5797 #if defined(PETSC_HAVE_TRIANGLE)
5798       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5799 #else
5800       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5801 #endif
5802     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5803     break;
5804   case 2:
5805     if (!name || isCTetgen) {
5806 #if defined(PETSC_HAVE_CTETGEN)
5807       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5808 #else
5809       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5810 #endif
5811     } else if (isTetgen) {
5812 #if defined(PETSC_HAVE_TETGEN)
5813       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5814 #else
5815       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5816 #endif
5817     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5818     break;
5819   default:
5820     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5821   }
5822   PetscFunctionReturn(0);
5823 }
5824 
5825 typedef PetscInt CellRefiner;
5826 
5827 #undef __FUNCT__
5828 #define __FUNCT__ "GetDepthStart_Private"
5829 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5830 {
5831   PetscFunctionBegin;
5832   if (cStart) *cStart = 0;
5833   if (vStart) *vStart = depthSize[depth];
5834   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5835   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5836   PetscFunctionReturn(0);
5837 }
5838 
5839 #undef __FUNCT__
5840 #define __FUNCT__ "GetDepthEnd_Private"
5841 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5842 {
5843   PetscFunctionBegin;
5844   if (cEnd) *cEnd = depthSize[depth];
5845   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5846   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5847   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5848   PetscFunctionReturn(0);
5849 }
5850 
5851 #undef __FUNCT__
5852 #define __FUNCT__ "CellRefinerGetSizes"
5853 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5854 {
5855   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5856   PetscErrorCode ierr;
5857 
5858   PetscFunctionBegin;
5859   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5860   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5861   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5862   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5863   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5864   switch (refiner) {
5865   case 1:
5866     /* Simplicial 2D */
5867     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5868     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5869     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5870     break;
5871   case 3:
5872     /* Hybrid 2D */
5873     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5874     cMax = PetscMin(cEnd, cMax);
5875     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5876     fMax         = PetscMin(fEnd, fMax);
5877     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5878     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 */
5879     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5880     break;
5881   case 2:
5882     /* Hex 2D */
5883     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5884     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5885     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5886     break;
5887   default:
5888     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5889   }
5890   PetscFunctionReturn(0);
5891 }
5892 
5893 #undef __FUNCT__
5894 #define __FUNCT__ "CellRefinerSetConeSizes"
5895 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5896 {
5897   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5898   PetscErrorCode ierr;
5899 
5900   PetscFunctionBegin;
5901   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5902   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5903   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5904   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5905   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5906   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5907   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5908   switch (refiner) {
5909   case 1:
5910     /* Simplicial 2D */
5911     /* All cells have 3 faces */
5912     for (c = cStart; c < cEnd; ++c) {
5913       for (r = 0; r < 4; ++r) {
5914         const PetscInt newp = (c - cStart)*4 + r;
5915 
5916         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5917       }
5918     }
5919     /* Split faces have 2 vertices and the same cells as the parent */
5920     for (f = fStart; f < fEnd; ++f) {
5921       for (r = 0; r < 2; ++r) {
5922         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5923         PetscInt       size;
5924 
5925         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5926         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5927         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5928       }
5929     }
5930     /* Interior faces have 2 vertices and 2 cells */
5931     for (c = cStart; c < cEnd; ++c) {
5932       for (r = 0; r < 3; ++r) {
5933         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5934 
5935         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5936         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5937       }
5938     }
5939     /* Old vertices have identical supports */
5940     for (v = vStart; v < vEnd; ++v) {
5941       const PetscInt newp = vStartNew + (v - vStart);
5942       PetscInt       size;
5943 
5944       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5945       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5946     }
5947     /* Face vertices have 2 + cells*2 supports */
5948     for (f = fStart; f < fEnd; ++f) {
5949       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5950       PetscInt       size;
5951 
5952       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5953       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5954     }
5955     break;
5956   case 2:
5957     /* Hex 2D */
5958     /* All cells have 4 faces */
5959     for (c = cStart; c < cEnd; ++c) {
5960       for (r = 0; r < 4; ++r) {
5961         const PetscInt newp = (c - cStart)*4 + r;
5962 
5963         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5964       }
5965     }
5966     /* Split faces have 2 vertices and the same cells as the parent */
5967     for (f = fStart; f < fEnd; ++f) {
5968       for (r = 0; r < 2; ++r) {
5969         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5970         PetscInt       size;
5971 
5972         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5973         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5974         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5975       }
5976     }
5977     /* Interior faces have 2 vertices and 2 cells */
5978     for (c = cStart; c < cEnd; ++c) {
5979       for (r = 0; r < 4; ++r) {
5980         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5981 
5982         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5983         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5984       }
5985     }
5986     /* Old vertices have identical supports */
5987     for (v = vStart; v < vEnd; ++v) {
5988       const PetscInt newp = vStartNew + (v - vStart);
5989       PetscInt       size;
5990 
5991       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5992       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5993     }
5994     /* Face vertices have 2 + cells supports */
5995     for (f = fStart; f < fEnd; ++f) {
5996       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5997       PetscInt       size;
5998 
5999       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6000       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
6001     }
6002     /* Cell vertices have 4 supports */
6003     for (c = cStart; c < cEnd; ++c) {
6004       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6005 
6006       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
6007     }
6008     break;
6009   case 3:
6010     /* Hybrid 2D */
6011     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6012     cMax = PetscMin(cEnd, cMax);
6013     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6014     fMax = PetscMin(fEnd, fMax);
6015     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6016     /* Interior cells have 3 faces */
6017     for (c = cStart; c < cMax; ++c) {
6018       for (r = 0; r < 4; ++r) {
6019         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
6020 
6021         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
6022       }
6023     }
6024     /* Hybrid cells have 4 faces */
6025     for (c = cMax; c < cEnd; ++c) {
6026       for (r = 0; r < 2; ++r) {
6027         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
6028 
6029         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6030       }
6031     }
6032     /* Interior split faces have 2 vertices and the same cells as the parent */
6033     for (f = fStart; f < fMax; ++f) {
6034       for (r = 0; r < 2; ++r) {
6035         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6036         PetscInt       size;
6037 
6038         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6039         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6040         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6041       }
6042     }
6043     /* Interior cell faces have 2 vertices and 2 cells */
6044     for (c = cStart; c < cMax; ++c) {
6045       for (r = 0; r < 3; ++r) {
6046         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6047 
6048         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6049         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6050       }
6051     }
6052     /* Hybrid faces have 2 vertices and the same cells */
6053     for (f = fMax; f < fEnd; ++f) {
6054       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6055       PetscInt       size;
6056 
6057       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6058       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6059       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6060     }
6061     /* Hybrid cell faces have 2 vertices and 2 cells */
6062     for (c = cMax; c < cEnd; ++c) {
6063       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6064 
6065       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6066       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6067     }
6068     /* Old vertices have identical supports */
6069     for (v = vStart; v < vEnd; ++v) {
6070       const PetscInt newp = vStartNew + (v - vStart);
6071       PetscInt       size;
6072 
6073       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6074       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6075     }
6076     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6077     for (f = fStart; f < fMax; ++f) {
6078       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6079       const PetscInt *support;
6080       PetscInt       size, newSize = 2, s;
6081 
6082       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6083       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6084       for (s = 0; s < size; ++s) {
6085         if (support[s] >= cMax) newSize += 1;
6086         else newSize += 2;
6087       }
6088       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6089     }
6090     break;
6091   default:
6092     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6093   }
6094   PetscFunctionReturn(0);
6095 }
6096 
6097 #undef __FUNCT__
6098 #define __FUNCT__ "CellRefinerSetCones"
6099 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6100 {
6101   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;
6102   PetscInt       maxSupportSize, *supportRef;
6103   PetscErrorCode ierr;
6104 
6105   PetscFunctionBegin;
6106   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6107   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6108   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6109   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6110   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6111   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6112   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6113   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6114   switch (refiner) {
6115   case 1:
6116     /* Simplicial 2D */
6117     /*
6118      2
6119      |\
6120      | \
6121      |  \
6122      |   \
6123      | C  \
6124      |     \
6125      |      \
6126      2---1---1
6127      |\  D  / \
6128      | 2   0   \
6129      |A \ /  B  \
6130      0---0-------1
6131      */
6132     /* All cells have 3 faces */
6133     for (c = cStart; c < cEnd; ++c) {
6134       const PetscInt  newp = cStartNew + (c - cStart)*4;
6135       const PetscInt *cone, *ornt;
6136       PetscInt        coneNew[3], orntNew[3];
6137 
6138       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6139       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6140       /* A triangle */
6141       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6142       orntNew[0] = ornt[0];
6143       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6144       orntNew[1] = -2;
6145       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6146       orntNew[2] = ornt[2];
6147       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6148       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6149 #if 1
6150       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6151       for (p = 0; p < 3; ++p) {
6152         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6153       }
6154 #endif
6155       /* B triangle */
6156       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6157       orntNew[0] = ornt[0];
6158       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6159       orntNew[1] = ornt[1];
6160       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6161       orntNew[2] = -2;
6162       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6163       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6164 #if 1
6165       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6166       for (p = 0; p < 3; ++p) {
6167         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6168       }
6169 #endif
6170       /* C triangle */
6171       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6172       orntNew[0] = -2;
6173       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6174       orntNew[1] = ornt[1];
6175       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6176       orntNew[2] = ornt[2];
6177       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6178       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6179 #if 1
6180       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6181       for (p = 0; p < 3; ++p) {
6182         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6183       }
6184 #endif
6185       /* D triangle */
6186       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6187       orntNew[0] = 0;
6188       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6189       orntNew[1] = 0;
6190       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6191       orntNew[2] = 0;
6192       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6193       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6194 #if 1
6195       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6196       for (p = 0; p < 3; ++p) {
6197         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6198       }
6199 #endif
6200     }
6201     /* Split faces have 2 vertices and the same cells as the parent */
6202     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6203     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6204     for (f = fStart; f < fEnd; ++f) {
6205       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6206 
6207       for (r = 0; r < 2; ++r) {
6208         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6209         const PetscInt *cone, *support;
6210         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6211 
6212         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6213         coneNew[0]       = vStartNew + (cone[0] - vStart);
6214         coneNew[1]       = vStartNew + (cone[1] - vStart);
6215         coneNew[(r+1)%2] = newv;
6216         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6217 #if 1
6218         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6219         for (p = 0; p < 2; ++p) {
6220           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6221         }
6222 #endif
6223         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6224         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6225         for (s = 0; s < supportSize; ++s) {
6226           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6227           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6228           for (c = 0; c < coneSize; ++c) {
6229             if (cone[c] == f) break;
6230           }
6231           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6232         }
6233         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6234 #if 1
6235         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6236         for (p = 0; p < supportSize; ++p) {
6237           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6238         }
6239 #endif
6240       }
6241     }
6242     /* Interior faces have 2 vertices and 2 cells */
6243     for (c = cStart; c < cEnd; ++c) {
6244       const PetscInt *cone;
6245 
6246       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6247       for (r = 0; r < 3; ++r) {
6248         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6249         PetscInt       coneNew[2];
6250         PetscInt       supportNew[2];
6251 
6252         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6253         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6254         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6255 #if 1
6256         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6257         for (p = 0; p < 2; ++p) {
6258           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6259         }
6260 #endif
6261         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6262         supportNew[1] = (c - cStart)*4 + 3;
6263         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6264 #if 1
6265         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6266         for (p = 0; p < 2; ++p) {
6267           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6268         }
6269 #endif
6270       }
6271     }
6272     /* Old vertices have identical supports */
6273     for (v = vStart; v < vEnd; ++v) {
6274       const PetscInt  newp = vStartNew + (v - vStart);
6275       const PetscInt *support, *cone;
6276       PetscInt        size, s;
6277 
6278       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6279       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6280       for (s = 0; s < size; ++s) {
6281         PetscInt r = 0;
6282 
6283         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6284         if (cone[1] == v) r = 1;
6285         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6286       }
6287       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6288 #if 1
6289       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6290       for (p = 0; p < size; ++p) {
6291         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6292       }
6293 #endif
6294     }
6295     /* Face vertices have 2 + cells*2 supports */
6296     for (f = fStart; f < fEnd; ++f) {
6297       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6298       const PetscInt *cone, *support;
6299       PetscInt        size, s;
6300 
6301       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6302       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6303       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6304       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6305       for (s = 0; s < size; ++s) {
6306         PetscInt r = 0;
6307 
6308         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6309         if      (cone[1] == f) r = 1;
6310         else if (cone[2] == f) r = 2;
6311         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6312         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6313       }
6314       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6315 #if 1
6316       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6317       for (p = 0; p < 2+size*2; ++p) {
6318         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6319       }
6320 #endif
6321     }
6322     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6323     break;
6324   case 2:
6325     /* Hex 2D */
6326     /*
6327      3---------2---------2
6328      |         |         |
6329      |    D    2    C    |
6330      |         |         |
6331      3----3----0----1----1
6332      |         |         |
6333      |    A    0    B    |
6334      |         |         |
6335      0---------0---------1
6336      */
6337     /* All cells have 4 faces */
6338     for (c = cStart; c < cEnd; ++c) {
6339       const PetscInt  newp = (c - cStart)*4;
6340       const PetscInt *cone, *ornt;
6341       PetscInt        coneNew[4], orntNew[4];
6342 
6343       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6344       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6345       /* A quad */
6346       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6347       orntNew[0] = ornt[0];
6348       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6349       orntNew[1] = 0;
6350       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6351       orntNew[2] = -2;
6352       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6353       orntNew[3] = ornt[3];
6354       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6355       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6356 #if 1
6357       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6358       for (p = 0; p < 4; ++p) {
6359         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6360       }
6361 #endif
6362       /* B quad */
6363       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6364       orntNew[0] = ornt[0];
6365       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6366       orntNew[1] = ornt[1];
6367       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6368       orntNew[2] = 0;
6369       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6370       orntNew[3] = -2;
6371       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6372       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6373 #if 1
6374       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6375       for (p = 0; p < 4; ++p) {
6376         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6377       }
6378 #endif
6379       /* C quad */
6380       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6381       orntNew[0] = -2;
6382       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6383       orntNew[1] = ornt[1];
6384       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6385       orntNew[2] = ornt[2];
6386       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6387       orntNew[3] = 0;
6388       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6389       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6390 #if 1
6391       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6392       for (p = 0; p < 4; ++p) {
6393         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6394       }
6395 #endif
6396       /* D quad */
6397       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6398       orntNew[0] = 0;
6399       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6400       orntNew[1] = -2;
6401       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6402       orntNew[2] = ornt[2];
6403       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6404       orntNew[3] = ornt[3];
6405       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6406       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6407 #if 1
6408       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6409       for (p = 0; p < 4; ++p) {
6410         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6411       }
6412 #endif
6413     }
6414     /* Split faces have 2 vertices and the same cells as the parent */
6415     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6416     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6417     for (f = fStart; f < fEnd; ++f) {
6418       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6419 
6420       for (r = 0; r < 2; ++r) {
6421         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6422         const PetscInt *cone, *support;
6423         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6424 
6425         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6426         coneNew[0]       = vStartNew + (cone[0] - vStart);
6427         coneNew[1]       = vStartNew + (cone[1] - vStart);
6428         coneNew[(r+1)%2] = newv;
6429         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6430 #if 1
6431         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6432         for (p = 0; p < 2; ++p) {
6433           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6434         }
6435 #endif
6436         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6437         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6438         for (s = 0; s < supportSize; ++s) {
6439           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6440           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6441           for (c = 0; c < coneSize; ++c) {
6442             if (cone[c] == f) break;
6443           }
6444           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6445         }
6446         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6447 #if 1
6448         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6449         for (p = 0; p < supportSize; ++p) {
6450           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6451         }
6452 #endif
6453       }
6454     }
6455     /* Interior faces have 2 vertices and 2 cells */
6456     for (c = cStart; c < cEnd; ++c) {
6457       const PetscInt *cone;
6458       PetscInt        coneNew[2], supportNew[2];
6459 
6460       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6461       for (r = 0; r < 4; ++r) {
6462         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6463 
6464         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6465         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6466         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6467 #if 1
6468         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6469         for (p = 0; p < 2; ++p) {
6470           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6471         }
6472 #endif
6473         supportNew[0] = (c - cStart)*4 + r;
6474         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6475         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6476 #if 1
6477         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6478         for (p = 0; p < 2; ++p) {
6479           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6480         }
6481 #endif
6482       }
6483     }
6484     /* Old vertices have identical supports */
6485     for (v = vStart; v < vEnd; ++v) {
6486       const PetscInt  newp = vStartNew + (v - vStart);
6487       const PetscInt *support, *cone;
6488       PetscInt        size, s;
6489 
6490       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6491       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6492       for (s = 0; s < size; ++s) {
6493         PetscInt r = 0;
6494 
6495         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6496         if (cone[1] == v) r = 1;
6497         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6498       }
6499       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6500 #if 1
6501       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6502       for (p = 0; p < size; ++p) {
6503         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6504       }
6505 #endif
6506     }
6507     /* Face vertices have 2 + cells supports */
6508     for (f = fStart; f < fEnd; ++f) {
6509       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6510       const PetscInt *cone, *support;
6511       PetscInt        size, s;
6512 
6513       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6514       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6515       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6516       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6517       for (s = 0; s < size; ++s) {
6518         PetscInt r = 0;
6519 
6520         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6521         if      (cone[1] == f) r = 1;
6522         else if (cone[2] == f) r = 2;
6523         else if (cone[3] == f) r = 3;
6524         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6525       }
6526       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6527 #if 1
6528       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6529       for (p = 0; p < 2+size; ++p) {
6530         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6531       }
6532 #endif
6533     }
6534     /* Cell vertices have 4 supports */
6535     for (c = cStart; c < cEnd; ++c) {
6536       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6537       PetscInt       supportNew[4];
6538 
6539       for (r = 0; r < 4; ++r) {
6540         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6541       }
6542       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6543     }
6544     break;
6545   case 3:
6546     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6547     cMax = PetscMin(cEnd, cMax);
6548     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6549     fMax = PetscMin(fEnd, fMax);
6550     /* Interior cells have 3 faces */
6551     for (c = cStart; c < cMax; ++c) {
6552       const PetscInt  newp = cStartNew + (c - cStart)*4;
6553       const PetscInt *cone, *ornt;
6554       PetscInt        coneNew[3], orntNew[3];
6555 
6556       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6557       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6558       /* A triangle */
6559       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6560       orntNew[0] = ornt[0];
6561       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6562       orntNew[1] = -2;
6563       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6564       orntNew[2] = ornt[2];
6565       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6566       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6567 #if 1
6568       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6569       for (p = 0; p < 3; ++p) {
6570         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6571       }
6572 #endif
6573       /* B triangle */
6574       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6575       orntNew[0] = ornt[0];
6576       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6577       orntNew[1] = ornt[1];
6578       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6579       orntNew[2] = -2;
6580       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6581       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6582 #if 1
6583       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6584       for (p = 0; p < 3; ++p) {
6585         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6586       }
6587 #endif
6588       /* C triangle */
6589       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6590       orntNew[0] = -2;
6591       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6592       orntNew[1] = ornt[1];
6593       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6594       orntNew[2] = ornt[2];
6595       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6596       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6597 #if 1
6598       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6599       for (p = 0; p < 3; ++p) {
6600         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6601       }
6602 #endif
6603       /* D triangle */
6604       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6605       orntNew[0] = 0;
6606       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6607       orntNew[1] = 0;
6608       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6609       orntNew[2] = 0;
6610       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6611       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6612 #if 1
6613       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6614       for (p = 0; p < 3; ++p) {
6615         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6616       }
6617 #endif
6618     }
6619     /*
6620      2----3----3
6621      |         |
6622      |    B    |
6623      |         |
6624      0----4--- 1
6625      |         |
6626      |    A    |
6627      |         |
6628      0----2----1
6629      */
6630     /* Hybrid cells have 4 faces */
6631     for (c = cMax; c < cEnd; ++c) {
6632       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6633       const PetscInt *cone, *ornt;
6634       PetscInt        coneNew[4], orntNew[4];
6635 
6636       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6637       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6638       /* A quad */
6639       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6640       orntNew[0] = ornt[0];
6641       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6642       orntNew[1] = ornt[1];
6643       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6644       orntNew[2] = 0;
6645       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6646       orntNew[3] = 0;
6647       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6648       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6649 #if 1
6650       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6651       for (p = 0; p < 4; ++p) {
6652         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6653       }
6654 #endif
6655       /* B quad */
6656       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6657       orntNew[0] = ornt[0];
6658       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6659       orntNew[1] = ornt[1];
6660       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6661       orntNew[2] = 0;
6662       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6663       orntNew[3] = 0;
6664       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6665       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6666 #if 1
6667       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6668       for (p = 0; p < 4; ++p) {
6669         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6670       }
6671 #endif
6672     }
6673     /* Interior split faces have 2 vertices and the same cells as the parent */
6674     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6675     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6676     for (f = fStart; f < fMax; ++f) {
6677       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6678 
6679       for (r = 0; r < 2; ++r) {
6680         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6681         const PetscInt *cone, *support;
6682         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6683 
6684         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6685         coneNew[0]       = vStartNew + (cone[0] - vStart);
6686         coneNew[1]       = vStartNew + (cone[1] - vStart);
6687         coneNew[(r+1)%2] = newv;
6688         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6689 #if 1
6690         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6691         for (p = 0; p < 2; ++p) {
6692           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6693         }
6694 #endif
6695         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6696         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6697         for (s = 0; s < supportSize; ++s) {
6698           if (support[s] >= cMax) {
6699             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6700           } else {
6701             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6702             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6703             for (c = 0; c < coneSize; ++c) {
6704               if (cone[c] == f) break;
6705             }
6706             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6707           }
6708         }
6709         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6710 #if 1
6711         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6712         for (p = 0; p < supportSize; ++p) {
6713           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6714         }
6715 #endif
6716       }
6717     }
6718     /* Interior cell faces have 2 vertices and 2 cells */
6719     for (c = cStart; c < cMax; ++c) {
6720       const PetscInt *cone;
6721 
6722       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6723       for (r = 0; r < 3; ++r) {
6724         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6725         PetscInt       coneNew[2];
6726         PetscInt       supportNew[2];
6727 
6728         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6729         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6730         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6731 #if 1
6732         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6733         for (p = 0; p < 2; ++p) {
6734           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6735         }
6736 #endif
6737         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6738         supportNew[1] = (c - cStart)*4 + 3;
6739         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6740 #if 1
6741         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6742         for (p = 0; p < 2; ++p) {
6743           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6744         }
6745 #endif
6746       }
6747     }
6748     /* Interior hybrid faces have 2 vertices and the same cells */
6749     for (f = fMax; f < fEnd; ++f) {
6750       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6751       const PetscInt *cone;
6752       const PetscInt *support;
6753       PetscInt        coneNew[2];
6754       PetscInt        supportNew[2];
6755       PetscInt        size, s, r;
6756 
6757       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6758       coneNew[0] = vStartNew + (cone[0] - vStart);
6759       coneNew[1] = vStartNew + (cone[1] - vStart);
6760       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6761 #if 1
6762       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6763       for (p = 0; p < 2; ++p) {
6764         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6765       }
6766 #endif
6767       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6768       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6769       for (s = 0; s < size; ++s) {
6770         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6771         for (r = 0; r < 2; ++r) {
6772           if (cone[r+2] == f) break;
6773         }
6774         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6775       }
6776       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6777 #if 1
6778       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6779       for (p = 0; p < size; ++p) {
6780         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6781       }
6782 #endif
6783     }
6784     /* Cell hybrid faces have 2 vertices and 2 cells */
6785     for (c = cMax; c < cEnd; ++c) {
6786       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6787       const PetscInt *cone;
6788       PetscInt        coneNew[2];
6789       PetscInt        supportNew[2];
6790 
6791       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6792       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6793       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6794       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6795 #if 1
6796       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6797       for (p = 0; p < 2; ++p) {
6798         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6799       }
6800 #endif
6801       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6802       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6803       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6804 #if 1
6805       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6806       for (p = 0; p < 2; ++p) {
6807         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6808       }
6809 #endif
6810     }
6811     /* Old vertices have identical supports */
6812     for (v = vStart; v < vEnd; ++v) {
6813       const PetscInt  newp = vStartNew + (v - vStart);
6814       const PetscInt *support, *cone;
6815       PetscInt        size, s;
6816 
6817       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6818       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6819       for (s = 0; s < size; ++s) {
6820         if (support[s] >= fMax) {
6821           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6822         } else {
6823           PetscInt r = 0;
6824 
6825           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6826           if (cone[1] == v) r = 1;
6827           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6828         }
6829       }
6830       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6831 #if 1
6832       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6833       for (p = 0; p < size; ++p) {
6834         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6835       }
6836 #endif
6837     }
6838     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6839     for (f = fStart; f < fMax; ++f) {
6840       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6841       const PetscInt *cone, *support;
6842       PetscInt        size, newSize = 2, s;
6843 
6844       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6845       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6846       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6847       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6848       for (s = 0; s < size; ++s) {
6849         PetscInt r = 0;
6850 
6851         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6852         if (support[s] >= cMax) {
6853           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6854 
6855           newSize += 1;
6856         } else {
6857           if      (cone[1] == f) r = 1;
6858           else if (cone[2] == f) r = 2;
6859           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6860           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6861 
6862           newSize += 2;
6863         }
6864       }
6865       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6866 #if 1
6867       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6868       for (p = 0; p < newSize; ++p) {
6869         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6870       }
6871 #endif
6872     }
6873     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6874     break;
6875   default:
6876     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6877   }
6878   PetscFunctionReturn(0);
6879 }
6880 
6881 #undef __FUNCT__
6882 #define __FUNCT__ "CellRefinerSetCoordinates"
6883 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6884 {
6885   PetscSection   coordSection, coordSectionNew;
6886   Vec            coordinates, coordinatesNew;
6887   PetscScalar   *coords, *coordsNew;
6888   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6889   PetscErrorCode ierr;
6890 
6891   PetscFunctionBegin;
6892   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6893   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6894   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6895   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6896   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6897   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6898   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6899   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6900   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6901   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6902   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6903   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6904   if (fMax < 0) fMax = fEnd;
6905   switch (refiner) {
6906   case 1:
6907   case 2:
6908   case 3:
6909     /* Simplicial and Hex 2D */
6910     /* All vertices have the dim coordinates */
6911     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6912       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6913       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6914     }
6915     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6916     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6917     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6918     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6919     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
6920     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6921     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6922     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6923     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6924     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6925     /* Old vertices have the same coordinates */
6926     for (v = vStart; v < vEnd; ++v) {
6927       const PetscInt newv = vStartNew + (v - vStart);
6928       PetscInt       off, offnew, d;
6929 
6930       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6931       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6932       for (d = 0; d < dim; ++d) {
6933         coordsNew[offnew+d] = coords[off+d];
6934       }
6935     }
6936     /* Face vertices have the average of endpoint coordinates */
6937     for (f = fStart; f < fMax; ++f) {
6938       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6939       const PetscInt *cone;
6940       PetscInt        coneSize, offA, offB, offnew, d;
6941 
6942       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6943       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6944       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6945       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6946       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6947       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6948       for (d = 0; d < dim; ++d) {
6949         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6950       }
6951     }
6952     /* Just Hex 2D */
6953     if (refiner == 2) {
6954       /* Cell vertices have the average of corner coordinates */
6955       for (c = cStart; c < cEnd; ++c) {
6956         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6957         PetscInt      *cone = NULL;
6958         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6959 
6960         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6961         for (p = 0; p < closureSize*2; p += 2) {
6962           const PetscInt point = cone[p];
6963           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6964         }
6965         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6966         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6967         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6968         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6969         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6970         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6971         for (d = 0; d < dim; ++d) {
6972           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6973         }
6974         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6975       }
6976     }
6977     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6978     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6979     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6980     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6981     break;
6982   default:
6983     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6984   }
6985   PetscFunctionReturn(0);
6986 }
6987 
6988 #undef __FUNCT__
6989 #define __FUNCT__ "DMPlexCreateProcessSF"
6990 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6991 {
6992   PetscInt           numRoots, numLeaves, l;
6993   const PetscInt    *localPoints;
6994   const PetscSFNode *remotePoints;
6995   PetscInt          *localPointsNew;
6996   PetscSFNode       *remotePointsNew;
6997   PetscInt          *ranks, *ranksNew;
6998   PetscErrorCode     ierr;
6999 
7000   PetscFunctionBegin;
7001   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7002   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
7003   for (l = 0; l < numLeaves; ++l) {
7004     ranks[l] = remotePoints[l].rank;
7005   }
7006   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
7007   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
7008   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7009   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7010   for (l = 0; l < numLeaves; ++l) {
7011     ranksNew[l]              = ranks[l];
7012     localPointsNew[l]        = l;
7013     remotePointsNew[l].index = 0;
7014     remotePointsNew[l].rank  = ranksNew[l];
7015   }
7016   ierr = PetscFree(ranks);CHKERRQ(ierr);
7017   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
7018   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
7019   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7020   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7021   PetscFunctionReturn(0);
7022 }
7023 
7024 #undef __FUNCT__
7025 #define __FUNCT__ "CellRefinerCreateSF"
7026 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7027 {
7028   PetscSF            sf, sfNew, sfProcess;
7029   IS                 processRanks;
7030   MPI_Datatype       depthType;
7031   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7032   const PetscInt    *localPoints, *neighbors;
7033   const PetscSFNode *remotePoints;
7034   PetscInt          *localPointsNew;
7035   PetscSFNode       *remotePointsNew;
7036   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7037   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7038   PetscErrorCode     ierr;
7039 
7040   PetscFunctionBegin;
7041   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7042   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7043   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7044   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7045   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7046   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7047   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7048   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7049   switch (refiner) {
7050   case 3:
7051     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7052     cMax = PetscMin(cEnd, cMax);
7053     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7054     fMax = PetscMin(fEnd, fMax);
7055   }
7056   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7057   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7058   /* Caculate size of new SF */
7059   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7060   if (numRoots < 0) PetscFunctionReturn(0);
7061   for (l = 0; l < numLeaves; ++l) {
7062     const PetscInt p = localPoints[l];
7063 
7064     switch (refiner) {
7065     case 1:
7066       /* Simplicial 2D */
7067       if ((p >= vStart) && (p < vEnd)) {
7068         /* Old vertices stay the same */
7069         ++numLeavesNew;
7070       } else if ((p >= fStart) && (p < fEnd)) {
7071         /* Old faces add new faces and vertex */
7072         numLeavesNew += 1 + 2;
7073       } else if ((p >= cStart) && (p < cEnd)) {
7074         /* Old cells add new cells and interior faces */
7075         numLeavesNew += 4 + 3;
7076       }
7077       break;
7078     case 2:
7079       /* Hex 2D */
7080       if ((p >= vStart) && (p < vEnd)) {
7081         /* Old vertices stay the same */
7082         ++numLeavesNew;
7083       } else if ((p >= fStart) && (p < fEnd)) {
7084         /* Old faces add new faces and vertex */
7085         numLeavesNew += 1 + 2;
7086       } else if ((p >= cStart) && (p < cEnd)) {
7087         /* Old cells add new cells and interior faces */
7088         numLeavesNew += 4 + 4;
7089       }
7090       break;
7091     default:
7092       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7093     }
7094   }
7095   /* Communicate depthSizes for each remote rank */
7096   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7097   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7098   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7099   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);
7100   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7101   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7102   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7103   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7104   for (n = 0; n < numNeighbors; ++n) {
7105     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7106   }
7107   depthSizeOld[depth]   = cMax;
7108   depthSizeOld[0]       = vMax;
7109   depthSizeOld[depth-1] = fMax;
7110   depthSizeOld[1]       = eMax;
7111 
7112   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7113   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7114 
7115   depthSizeOld[depth]   = cEnd - cStart;
7116   depthSizeOld[0]       = vEnd - vStart;
7117   depthSizeOld[depth-1] = fEnd - fStart;
7118   depthSizeOld[1]       = eEnd - eStart;
7119 
7120   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7121   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7122   for (n = 0; n < numNeighbors; ++n) {
7123     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7124   }
7125   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7126   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7127   /* Calculate new point SF */
7128   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7129   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7130   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7131   for (l = 0, m = 0; l < numLeaves; ++l) {
7132     PetscInt    p     = localPoints[l];
7133     PetscInt    rp    = remotePoints[l].index, n;
7134     PetscMPIInt rrank = remotePoints[l].rank;
7135 
7136     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7137     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7138     switch (refiner) {
7139     case 1:
7140       /* Simplicial 2D */
7141       if ((p >= vStart) && (p < vEnd)) {
7142         /* Old vertices stay the same */
7143         localPointsNew[m]        = vStartNew     + (p  - vStart);
7144         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7145         remotePointsNew[m].rank  = rrank;
7146         ++m;
7147       } else if ((p >= fStart) && (p < fEnd)) {
7148         /* Old faces add new faces and vertex */
7149         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7150         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7151         remotePointsNew[m].rank  = rrank;
7152         ++m;
7153         for (r = 0; r < 2; ++r, ++m) {
7154           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7155           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7156           remotePointsNew[m].rank  = rrank;
7157         }
7158       } else if ((p >= cStart) && (p < cEnd)) {
7159         /* Old cells add new cells and interior faces */
7160         for (r = 0; r < 4; ++r, ++m) {
7161           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7162           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7163           remotePointsNew[m].rank  = rrank;
7164         }
7165         for (r = 0; r < 3; ++r, ++m) {
7166           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7167           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7168           remotePointsNew[m].rank  = rrank;
7169         }
7170       }
7171       break;
7172     case 2:
7173       /* Hex 2D */
7174       if ((p >= vStart) && (p < vEnd)) {
7175         /* Old vertices stay the same */
7176         localPointsNew[m]        = vStartNew     + (p  - vStart);
7177         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7178         remotePointsNew[m].rank  = rrank;
7179         ++m;
7180       } else if ((p >= fStart) && (p < fEnd)) {
7181         /* Old faces add new faces and vertex */
7182         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7183         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7184         remotePointsNew[m].rank  = rrank;
7185         ++m;
7186         for (r = 0; r < 2; ++r, ++m) {
7187           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7188           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7189           remotePointsNew[m].rank  = rrank;
7190         }
7191       } else if ((p >= cStart) && (p < cEnd)) {
7192         /* Old cells add new cells and interior faces */
7193         for (r = 0; r < 4; ++r, ++m) {
7194           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7195           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7196           remotePointsNew[m].rank  = rrank;
7197         }
7198         for (r = 0; r < 4; ++r, ++m) {
7199           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7200           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7201           remotePointsNew[m].rank  = rrank;
7202         }
7203       }
7204       break;
7205     case 3:
7206       /* Hybrid simplicial 2D */
7207       if ((p >= vStart) && (p < vEnd)) {
7208         /* Old vertices stay the same */
7209         localPointsNew[m]        = vStartNew     + (p  - vStart);
7210         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7211         remotePointsNew[m].rank  = rrank;
7212         ++m;
7213       } else if ((p >= fStart) && (p < fMax)) {
7214         /* Old interior faces add new faces and vertex */
7215         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7216         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7217         remotePointsNew[m].rank  = rrank;
7218         ++m;
7219         for (r = 0; r < 2; ++r, ++m) {
7220           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7221           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7222           remotePointsNew[m].rank  = rrank;
7223         }
7224       } else if ((p >= fMax) && (p < fEnd)) {
7225         /* Old hybrid faces stay the same */
7226         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7227         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7228         remotePointsNew[m].rank  = rrank;
7229         ++m;
7230       } else if ((p >= cStart) && (p < cMax)) {
7231         /* Old interior cells add new cells and interior faces */
7232         for (r = 0; r < 4; ++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         for (r = 0; r < 3; ++r, ++m) {
7238           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7239           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7240           remotePointsNew[m].rank  = rrank;
7241         }
7242       } else if ((p >= cStart) && (p < cMax)) {
7243         /* Old hybrid cells add new cells and hybrid face */
7244         for (r = 0; r < 2; ++r, ++m) {
7245           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7246           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7247           remotePointsNew[m].rank  = rrank;
7248         }
7249         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7250         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]);
7251         remotePointsNew[m].rank  = rrank;
7252         ++m;
7253       }
7254       break;
7255     default:
7256       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7257     }
7258   }
7259   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7260   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7261   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7262   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7263   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7264   PetscFunctionReturn(0);
7265 }
7266 
7267 #undef __FUNCT__
7268 #define __FUNCT__ "CellRefinerCreateLabels"
7269 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7270 {
7271   PetscInt       numLabels, l;
7272   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7273   PetscErrorCode ierr;
7274 
7275   PetscFunctionBegin;
7276   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7277   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7278   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7279   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7280 
7281   cStartNew = 0;
7282   vStartNew = depthSize[2];
7283   fStartNew = depthSize[2] + depthSize[0];
7284 
7285   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7286   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7287   switch (refiner) {
7288   case 3:
7289     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7290     cMax = PetscMin(cEnd, cMax);
7291     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7292     fMax = PetscMin(fEnd, fMax);
7293   }
7294   for (l = 0; l < numLabels; ++l) {
7295     DMLabel         label, labelNew;
7296     const char     *lname;
7297     PetscBool       isDepth;
7298     IS              valueIS;
7299     const PetscInt *values;
7300     PetscInt        numValues, val;
7301 
7302     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7303     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7304     if (isDepth) continue;
7305     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7306     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7307     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7308     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7309     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7310     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7311     for (val = 0; val < numValues; ++val) {
7312       IS              pointIS;
7313       const PetscInt *points;
7314       PetscInt        numPoints, n;
7315 
7316       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7317       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7318       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7319       for (n = 0; n < numPoints; ++n) {
7320         const PetscInt p = points[n];
7321         switch (refiner) {
7322         case 1:
7323           /* Simplicial 2D */
7324           if ((p >= vStart) && (p < vEnd)) {
7325             /* Old vertices stay the same */
7326             newp = vStartNew + (p - vStart);
7327             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7328           } else if ((p >= fStart) && (p < fEnd)) {
7329             /* Old faces add new faces and vertex */
7330             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7331             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7332             for (r = 0; r < 2; ++r) {
7333               newp = fStartNew + (p - fStart)*2 + r;
7334               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7335             }
7336           } else if ((p >= cStart) && (p < cEnd)) {
7337             /* Old cells add new cells and interior faces */
7338             for (r = 0; r < 4; ++r) {
7339               newp = cStartNew + (p - cStart)*4 + r;
7340               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7341             }
7342             for (r = 0; r < 3; ++r) {
7343               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7344               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7345             }
7346           }
7347           break;
7348         case 2:
7349           /* Hex 2D */
7350           if ((p >= vStart) && (p < vEnd)) {
7351             /* Old vertices stay the same */
7352             newp = vStartNew + (p - vStart);
7353             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7354           } else if ((p >= fStart) && (p < fEnd)) {
7355             /* Old faces add new faces and vertex */
7356             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7357             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7358             for (r = 0; r < 2; ++r) {
7359               newp = fStartNew + (p - fStart)*2 + r;
7360               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7361             }
7362           } else if ((p >= cStart) && (p < cEnd)) {
7363             /* Old cells add new cells and interior faces and vertex */
7364             for (r = 0; r < 4; ++r) {
7365               newp = cStartNew + (p - cStart)*4 + r;
7366               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7367             }
7368             for (r = 0; r < 4; ++r) {
7369               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7370               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7371             }
7372             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7373             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7374           }
7375           break;
7376         case 3:
7377           /* Hybrid simplicial 2D */
7378           if ((p >= vStart) && (p < vEnd)) {
7379             /* Old vertices stay the same */
7380             newp = vStartNew + (p - vStart);
7381             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7382           } else if ((p >= fStart) && (p < fMax)) {
7383             /* Old interior faces add new faces and vertex */
7384             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7385             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7386             for (r = 0; r < 2; ++r) {
7387               newp = fStartNew + (p - fStart)*2 + r;
7388               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7389             }
7390           } else if ((p >= fMax) && (p < fEnd)) {
7391             /* Old hybrid faces stay the same */
7392             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7393             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7394           } else if ((p >= cStart) && (p < cMax)) {
7395             /* Old interior cells add new cells and interior faces */
7396             for (r = 0; r < 4; ++r) {
7397               newp = cStartNew + (p - cStart)*4 + r;
7398               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7399             }
7400             for (r = 0; r < 3; ++r) {
7401               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7402               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7403             }
7404           } else if ((p >= cMax) && (p < cEnd)) {
7405             /* Old hybrid cells add new cells and hybrid face */
7406             for (r = 0; r < 2; ++r) {
7407               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7408               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7409             }
7410             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7411             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7412           }
7413           break;
7414         default:
7415           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7416         }
7417       }
7418       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7419       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7420     }
7421     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7422     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7423     if (0) {
7424       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7425       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7426       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7427     }
7428   }
7429   PetscFunctionReturn(0);
7430 }
7431 
7432 #undef __FUNCT__
7433 #define __FUNCT__ "DMPlexRefine_Uniform"
7434 /* This will only work for interpolated meshes */
7435 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7436 {
7437   DM             rdm;
7438   PetscInt      *depthSize;
7439   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7440   PetscErrorCode ierr;
7441 
7442   PetscFunctionBegin;
7443   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
7444   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7445   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7446   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7447   /* Calculate number of new points of each depth */
7448   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7449   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7450   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7451   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7452   /* Step 1: Set chart */
7453   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7454   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7455   /* Step 2: Set cone/support sizes */
7456   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7457   /* Step 3: Setup refined DM */
7458   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7459   /* Step 4: Set cones and supports */
7460   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7461   /* Step 5: Stratify */
7462   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7463   /* Step 6: Set coordinates for vertices */
7464   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7465   /* Step 7: Create pointSF */
7466   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7467   /* Step 8: Create labels */
7468   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7469   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7470 
7471   *dmRefined = rdm;
7472   PetscFunctionReturn(0);
7473 }
7474 
7475 #undef __FUNCT__
7476 #define __FUNCT__ "DMPlexSetRefinementUniform"
7477 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7478 {
7479   DM_Plex *mesh = (DM_Plex*) dm->data;
7480 
7481   PetscFunctionBegin;
7482   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7483   mesh->refinementUniform = refinementUniform;
7484   PetscFunctionReturn(0);
7485 }
7486 
7487 #undef __FUNCT__
7488 #define __FUNCT__ "DMPlexGetRefinementUniform"
7489 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7490 {
7491   DM_Plex *mesh = (DM_Plex*) dm->data;
7492 
7493   PetscFunctionBegin;
7494   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7495   PetscValidPointer(refinementUniform,  2);
7496   *refinementUniform = mesh->refinementUniform;
7497   PetscFunctionReturn(0);
7498 }
7499 
7500 #undef __FUNCT__
7501 #define __FUNCT__ "DMPlexSetRefinementLimit"
7502 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7503 {
7504   DM_Plex *mesh = (DM_Plex*) dm->data;
7505 
7506   PetscFunctionBegin;
7507   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7508   mesh->refinementLimit = refinementLimit;
7509   PetscFunctionReturn(0);
7510 }
7511 
7512 #undef __FUNCT__
7513 #define __FUNCT__ "DMPlexGetRefinementLimit"
7514 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7515 {
7516   DM_Plex *mesh = (DM_Plex*) dm->data;
7517 
7518   PetscFunctionBegin;
7519   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7520   PetscValidPointer(refinementLimit,  2);
7521   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7522   *refinementLimit = mesh->refinementLimit;
7523   PetscFunctionReturn(0);
7524 }
7525 
7526 #undef __FUNCT__
7527 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7528 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7529 {
7530   PetscInt       dim, cStart, coneSize, cMax;
7531   PetscErrorCode ierr;
7532 
7533   PetscFunctionBegin;
7534   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7535   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7536   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7537   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7538   switch (dim) {
7539   case 2:
7540     switch (coneSize) {
7541     case 3:
7542       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7543       else *cellRefiner = 1; /* Triangular */
7544       break;
7545     case 4:
7546       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7547       else *cellRefiner = 2; /* Quadrilateral */
7548       break;
7549     default:
7550       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7551     }
7552     break;
7553   default:
7554     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7555   }
7556   PetscFunctionReturn(0);
7557 }
7558 
7559 #undef __FUNCT__
7560 #define __FUNCT__ "DMRefine_Plex"
7561 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7562 {
7563   PetscReal      refinementLimit;
7564   PetscInt       dim, cStart, cEnd;
7565   char           genname[1024], *name = NULL;
7566   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7567   PetscErrorCode ierr;
7568 
7569   PetscFunctionBegin;
7570   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7571   if (isUniform) {
7572     CellRefiner cellRefiner;
7573 
7574     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7575     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7576     PetscFunctionReturn(0);
7577   }
7578   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7579   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7580   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7581   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7582   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7583   if (flg) name = genname;
7584   if (name) {
7585     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7586     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7587     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7588   }
7589   switch (dim) {
7590   case 2:
7591     if (!name || isTriangle) {
7592 #if defined(PETSC_HAVE_TRIANGLE)
7593       double  *maxVolumes;
7594       PetscInt c;
7595 
7596       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7597       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7598       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7599 #else
7600       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7601 #endif
7602     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7603     break;
7604   case 3:
7605     if (!name || isCTetgen) {
7606 #if defined(PETSC_HAVE_CTETGEN)
7607       PetscReal *maxVolumes;
7608       PetscInt   c;
7609 
7610       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7611       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7612       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7613 #else
7614       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7615 #endif
7616     } else if (isTetgen) {
7617 #if defined(PETSC_HAVE_TETGEN)
7618       double  *maxVolumes;
7619       PetscInt c;
7620 
7621       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7622       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7623       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7624 #else
7625       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7626 #endif
7627     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7628     break;
7629   default:
7630     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7631   }
7632   PetscFunctionReturn(0);
7633 }
7634 
7635 #undef __FUNCT__
7636 #define __FUNCT__ "DMPlexGetDepth"
7637 /*@
7638   DMPlexGetDepth - get the number of strata
7639 
7640   Not Collective
7641 
7642   Input Parameters:
7643 . dm           - The DMPlex object
7644 
7645   Output Parameters:
7646 . depth - number of strata
7647 
7648   Level: developer
7649 
7650   Notes:
7651   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7652 
7653 .keywords: mesh, points
7654 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7655 @*/
7656 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7657 {
7658   PetscInt       d;
7659   PetscErrorCode ierr;
7660 
7661   PetscFunctionBegin;
7662   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7663   PetscValidPointer(depth, 2);
7664   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7665   *depth = d-1;
7666   PetscFunctionReturn(0);
7667 }
7668 
7669 #undef __FUNCT__
7670 #define __FUNCT__ "DMPlexGetDepthStratum"
7671 /*@
7672   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7673 
7674   Not Collective
7675 
7676   Input Parameters:
7677 + dm           - The DMPlex object
7678 - stratumValue - The requested depth
7679 
7680   Output Parameters:
7681 + start - The first point at this depth
7682 - end   - One beyond the last point at this depth
7683 
7684   Level: developer
7685 
7686 .keywords: mesh, points
7687 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7688 @*/
7689 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7690 {
7691   DM_Plex       *mesh = (DM_Plex*) dm->data;
7692   DMLabel        next  = mesh->labels;
7693   PetscBool      flg   = PETSC_FALSE;
7694   PetscInt       depth;
7695   PetscErrorCode ierr;
7696 
7697   PetscFunctionBegin;
7698   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7699   if (stratumValue < 0) {
7700     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7701     PetscFunctionReturn(0);
7702   } else {
7703     PetscInt pStart, pEnd;
7704 
7705     if (start) *start = 0;
7706     if (end)   *end   = 0;
7707     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7708     if (pStart == pEnd) PetscFunctionReturn(0);
7709   }
7710   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7711   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7712   /* We should have a generic GetLabel() and a Label class */
7713   while (next) {
7714     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7715     if (flg) break;
7716     next = next->next;
7717   }
7718   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7719   depth = stratumValue;
7720   if ((depth < 0) || (depth >= next->numStrata)) {
7721     if (start) *start = 0;
7722     if (end)   *end   = 0;
7723   } else {
7724     if (start) *start = next->points[next->stratumOffsets[depth]];
7725     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7726   }
7727   PetscFunctionReturn(0);
7728 }
7729 
7730 #undef __FUNCT__
7731 #define __FUNCT__ "DMPlexGetHeightStratum"
7732 /*@
7733   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7734 
7735   Not Collective
7736 
7737   Input Parameters:
7738 + dm           - The DMPlex object
7739 - stratumValue - The requested height
7740 
7741   Output Parameters:
7742 + start - The first point at this height
7743 - end   - One beyond the last point at this height
7744 
7745   Level: developer
7746 
7747 .keywords: mesh, points
7748 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7749 @*/
7750 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7751 {
7752   DM_Plex       *mesh = (DM_Plex*) dm->data;
7753   DMLabel        next  = mesh->labels;
7754   PetscBool      flg   = PETSC_FALSE;
7755   PetscInt       depth;
7756   PetscErrorCode ierr;
7757 
7758   PetscFunctionBegin;
7759   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7760   if (stratumValue < 0) {
7761     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7762   } else {
7763     PetscInt pStart, pEnd;
7764 
7765     if (start) *start = 0;
7766     if (end)   *end   = 0;
7767     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7768     if (pStart == pEnd) PetscFunctionReturn(0);
7769   }
7770   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7771   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7772   /* We should have a generic GetLabel() and a Label class */
7773   while (next) {
7774     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7775     if (flg) break;
7776     next = next->next;
7777   }
7778   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7779   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7780   if ((depth < 0) || (depth >= next->numStrata)) {
7781     if (start) *start = 0;
7782     if (end)   *end   = 0;
7783   } else {
7784     if (start) *start = next->points[next->stratumOffsets[depth]];
7785     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7786   }
7787   PetscFunctionReturn(0);
7788 }
7789 
7790 #undef __FUNCT__
7791 #define __FUNCT__ "DMPlexCreateSectionInitial"
7792 /* Set the number of dof on each point and separate by fields */
7793 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7794 {
7795   PetscInt      *numDofTot;
7796   PetscInt       pStart = 0, pEnd = 0;
7797   PetscInt       p, d, f;
7798   PetscErrorCode ierr;
7799 
7800   PetscFunctionBegin;
7801   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7802   for (d = 0; d <= dim; ++d) {
7803     numDofTot[d] = 0;
7804     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7805   }
7806   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
7807   if (numFields > 0) {
7808     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7809     if (numComp) {
7810       for (f = 0; f < numFields; ++f) {
7811         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7812       }
7813     }
7814   }
7815   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7816   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7817   for (d = 0; d <= dim; ++d) {
7818     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7819     for (p = pStart; p < pEnd; ++p) {
7820       for (f = 0; f < numFields; ++f) {
7821         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7822       }
7823       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7824     }
7825   }
7826   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7827   PetscFunctionReturn(0);
7828 }
7829 
7830 #undef __FUNCT__
7831 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7832 /* Set the number of dof on each point and separate by fields
7833    If constDof is PETSC_DETERMINE, constrain every dof on the point
7834 */
7835 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7836 {
7837   PetscInt       numFields;
7838   PetscInt       bc;
7839   PetscErrorCode ierr;
7840 
7841   PetscFunctionBegin;
7842   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7843   for (bc = 0; bc < numBC; ++bc) {
7844     PetscInt        field = 0;
7845     const PetscInt *idx;
7846     PetscInt        n, i;
7847 
7848     if (numFields) field = bcField[bc];
7849     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7850     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7851     for (i = 0; i < n; ++i) {
7852       const PetscInt p        = idx[i];
7853       PetscInt       numConst = constDof;
7854 
7855       /* Constrain every dof on the point */
7856       if (numConst < 0) {
7857         if (numFields) {
7858           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7859         } else {
7860           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7861         }
7862       }
7863       if (numFields) {
7864         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7865       }
7866       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7867     }
7868     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7869   }
7870   PetscFunctionReturn(0);
7871 }
7872 
7873 #undef __FUNCT__
7874 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7875 /* Set the constrained indices on each point and separate by fields */
7876 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7877 {
7878   PetscInt      *maxConstraints;
7879   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7880   PetscErrorCode ierr;
7881 
7882   PetscFunctionBegin;
7883   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7884   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7885   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7886   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7887   for (p = pStart; p < pEnd; ++p) {
7888     PetscInt cdof;
7889 
7890     if (numFields) {
7891       for (f = 0; f < numFields; ++f) {
7892         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7893         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7894       }
7895     } else {
7896       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7897       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7898     }
7899   }
7900   for (f = 0; f < numFields; ++f) {
7901     maxConstraints[numFields] += maxConstraints[f];
7902   }
7903   if (maxConstraints[numFields]) {
7904     PetscInt *indices;
7905 
7906     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7907     for (p = pStart; p < pEnd; ++p) {
7908       PetscInt cdof, d;
7909 
7910       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7911       if (cdof) {
7912         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7913         if (numFields) {
7914           PetscInt numConst = 0, foff = 0;
7915 
7916           for (f = 0; f < numFields; ++f) {
7917             PetscInt cfdof, fdof;
7918 
7919             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7920             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7921             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7922             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7923             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7924             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7925             numConst += cfdof;
7926             foff     += fdof;
7927           }
7928           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7929         } else {
7930           for (d = 0; d < cdof; ++d) indices[d] = d;
7931         }
7932         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7933       }
7934     }
7935     ierr = PetscFree(indices);CHKERRQ(ierr);
7936   }
7937   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7938   PetscFunctionReturn(0);
7939 }
7940 
7941 #undef __FUNCT__
7942 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7943 /* Set the constrained field indices on each point */
7944 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7945 {
7946   const PetscInt *points, *indices;
7947   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7948   PetscErrorCode  ierr;
7949 
7950   PetscFunctionBegin;
7951   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7952   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7953 
7954   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7955   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7956   if (!constraintIndices) {
7957     PetscInt *idx, i;
7958 
7959     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7960     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7961     for (i = 0; i < maxDof; ++i) idx[i] = i;
7962     for (p = 0; p < numPoints; ++p) {
7963       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7964     }
7965     ierr = PetscFree(idx);CHKERRQ(ierr);
7966   } else {
7967     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7968     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7969     for (p = 0; p < numPoints; ++p) {
7970       PetscInt fcdof;
7971 
7972       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7973       if (fcdof != numConstraints) SETERRQ4(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
7974       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7975     }
7976     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7977   }
7978   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7979   PetscFunctionReturn(0);
7980 }
7981 
7982 #undef __FUNCT__
7983 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7984 /* Set the constrained indices on each point and separate by fields */
7985 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7986 {
7987   PetscInt      *indices;
7988   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7989   PetscErrorCode ierr;
7990 
7991   PetscFunctionBegin;
7992   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7993   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7994   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7995   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7996   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7997   for (p = pStart; p < pEnd; ++p) {
7998     PetscInt cdof, d;
7999 
8000     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8001     if (cdof) {
8002       PetscInt numConst = 0, foff = 0;
8003 
8004       for (f = 0; f < numFields; ++f) {
8005         const PetscInt *fcind;
8006         PetscInt        fdof, fcdof;
8007 
8008         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8009         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8010         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8011         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8012         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
8013         foff     += fdof;
8014         numConst += fcdof;
8015       }
8016       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8017       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8018     }
8019   }
8020   ierr = PetscFree(indices);CHKERRQ(ierr);
8021   PetscFunctionReturn(0);
8022 }
8023 
8024 #undef __FUNCT__
8025 #define __FUNCT__ "DMPlexCreateSection"
8026 /*@C
8027   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8028 
8029   Not Collective
8030 
8031   Input Parameters:
8032 + dm        - The DMPlex object
8033 . dim       - The spatial dimension of the problem
8034 . numFields - The number of fields in the problem
8035 . numComp   - An array of size numFields that holds the number of components for each field
8036 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8037 . numBC     - The number of boundary conditions
8038 . bcField   - An array of size numBC giving the field number for each boundry condition
8039 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8040 
8041   Output Parameter:
8042 . section - The PetscSection object
8043 
8044   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
8045   nubmer of dof for field 0 on each edge.
8046 
8047   Level: developer
8048 
8049 .keywords: mesh, elements
8050 .seealso: DMPlexCreate(), PetscSectionCreate()
8051 @*/
8052 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8053 {
8054   PetscErrorCode ierr;
8055 
8056   PetscFunctionBegin;
8057   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8058   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8059   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8060   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8061   {
8062     PetscBool view = PETSC_FALSE;
8063 
8064     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8065     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8066   }
8067   PetscFunctionReturn(0);
8068 }
8069 
8070 #undef __FUNCT__
8071 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8072 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8073 {
8074   PetscSection   section;
8075   PetscErrorCode ierr;
8076 
8077   PetscFunctionBegin;
8078   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8079   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
8080   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8081   PetscFunctionReturn(0);
8082 }
8083 
8084 #undef __FUNCT__
8085 #define __FUNCT__ "DMPlexGetCoordinateSection"
8086 /*@
8087   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8088 
8089   Not Collective
8090 
8091   Input Parameter:
8092 . dm - The DMPlex object
8093 
8094   Output Parameter:
8095 . section - The PetscSection object
8096 
8097   Level: intermediate
8098 
8099 .keywords: mesh, coordinates
8100 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8101 @*/
8102 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8103 {
8104   DM             cdm;
8105   PetscErrorCode ierr;
8106 
8107   PetscFunctionBegin;
8108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8109   PetscValidPointer(section, 2);
8110   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8111   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8112   PetscFunctionReturn(0);
8113 }
8114 
8115 #undef __FUNCT__
8116 #define __FUNCT__ "DMPlexSetCoordinateSection"
8117 /*@
8118   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8119 
8120   Not Collective
8121 
8122   Input Parameters:
8123 + dm      - The DMPlex object
8124 - section - The PetscSection object
8125 
8126   Level: intermediate
8127 
8128 .keywords: mesh, coordinates
8129 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8130 @*/
8131 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8132 {
8133   DM             cdm;
8134   PetscErrorCode ierr;
8135 
8136   PetscFunctionBegin;
8137   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8138   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8139   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8140   PetscFunctionReturn(0);
8141 }
8142 
8143 #undef __FUNCT__
8144 #define __FUNCT__ "DMPlexGetConeSection"
8145 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8146 {
8147   DM_Plex *mesh = (DM_Plex*) dm->data;
8148 
8149   PetscFunctionBegin;
8150   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8151   if (section) *section = mesh->coneSection;
8152   PetscFunctionReturn(0);
8153 }
8154 
8155 #undef __FUNCT__
8156 #define __FUNCT__ "DMPlexGetCones"
8157 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8158 {
8159   DM_Plex *mesh = (DM_Plex*) dm->data;
8160 
8161   PetscFunctionBegin;
8162   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8163   if (cones) *cones = mesh->cones;
8164   PetscFunctionReturn(0);
8165 }
8166 
8167 #undef __FUNCT__
8168 #define __FUNCT__ "DMPlexGetConeOrientations"
8169 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8170 {
8171   DM_Plex *mesh = (DM_Plex*) dm->data;
8172 
8173   PetscFunctionBegin;
8174   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8175   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8176   PetscFunctionReturn(0);
8177 }
8178 
8179 #undef __FUNCT__
8180 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8181 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8182 {
8183   const PetscInt embedDim = 2;
8184   PetscReal      x        = PetscRealPart(point[0]);
8185   PetscReal      y        = PetscRealPart(point[1]);
8186   PetscReal      v0[2], J[4], invJ[4], detJ;
8187   PetscReal      xi, eta;
8188   PetscErrorCode ierr;
8189 
8190   PetscFunctionBegin;
8191   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8192   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8193   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8194 
8195   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
8196   else *cell = -1;
8197   PetscFunctionReturn(0);
8198 }
8199 
8200 #undef __FUNCT__
8201 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8202 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8203 {
8204   PetscSection       coordSection;
8205   Vec                coordsLocal;
8206   const PetscScalar *coords;
8207   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8208   PetscReal          x         = PetscRealPart(point[0]);
8209   PetscReal          y         = PetscRealPart(point[1]);
8210   PetscInt           crossings = 0, f;
8211   PetscErrorCode     ierr;
8212 
8213   PetscFunctionBegin;
8214   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8215   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8216   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8217   for (f = 0; f < 4; ++f) {
8218     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8219     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8220     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8221     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8222     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8223     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8224     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8225     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8226     if ((cond1 || cond2)  && above) ++crossings;
8227   }
8228   if (crossings % 2) *cell = c;
8229   else *cell = -1;
8230   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8231   PetscFunctionReturn(0);
8232 }
8233 
8234 #undef __FUNCT__
8235 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8236 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8237 {
8238   const PetscInt embedDim = 3;
8239   PetscReal      v0[3], J[9], invJ[9], detJ;
8240   PetscReal      x = PetscRealPart(point[0]);
8241   PetscReal      y = PetscRealPart(point[1]);
8242   PetscReal      z = PetscRealPart(point[2]);
8243   PetscReal      xi, eta, zeta;
8244   PetscErrorCode ierr;
8245 
8246   PetscFunctionBegin;
8247   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8248   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8249   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8250   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8251 
8252   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
8253   else *cell = -1;
8254   PetscFunctionReturn(0);
8255 }
8256 
8257 #undef __FUNCT__
8258 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8259 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8260 {
8261   PetscSection       coordSection;
8262   Vec                coordsLocal;
8263   const PetscScalar *coords;
8264   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8265                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8266   PetscBool          found = PETSC_TRUE;
8267   PetscInt           f;
8268   PetscErrorCode     ierr;
8269 
8270   PetscFunctionBegin;
8271   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8272   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8273   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8274   for (f = 0; f < 6; ++f) {
8275     /* Check the point is under plane */
8276     /*   Get face normal */
8277     PetscReal v_i[3];
8278     PetscReal v_j[3];
8279     PetscReal normal[3];
8280     PetscReal pp[3];
8281     PetscReal dot;
8282 
8283     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8284     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8285     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8286     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8287     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8288     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8289     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8290     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8291     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8292     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8293     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8294     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8295     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8296 
8297     /* Check that projected point is in face (2D location problem) */
8298     if (dot < 0.0) {
8299       found = PETSC_FALSE;
8300       break;
8301     }
8302   }
8303   if (found) *cell = c;
8304   else *cell = -1;
8305   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8306   PetscFunctionReturn(0);
8307 }
8308 
8309 #undef __FUNCT__
8310 #define __FUNCT__ "DMLocatePoints_Plex"
8311 /*
8312  Need to implement using the guess
8313 */
8314 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8315 {
8316   PetscInt       cell = -1 /*, guess = -1*/;
8317   PetscInt       bs, numPoints, p;
8318   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8319   PetscInt      *cells;
8320   PetscScalar   *a;
8321   PetscErrorCode ierr;
8322 
8323   PetscFunctionBegin;
8324   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8325   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8326   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
8327   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8328   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8329   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8330   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8331   if (bs != dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
8332   numPoints /= bs;
8333   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8334   for (p = 0; p < numPoints; ++p) {
8335     const PetscScalar *point = &a[p*bs];
8336 
8337     switch (dim) {
8338     case 2:
8339       for (c = cStart; c < cEnd; ++c) {
8340         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8341         switch (coneSize) {
8342         case 3:
8343           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8344           break;
8345         case 4:
8346           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8347           break;
8348         default:
8349           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8350         }
8351         if (cell >= 0) break;
8352       }
8353       break;
8354     case 3:
8355       for (c = cStart; c < cEnd; ++c) {
8356         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8357         switch (coneSize) {
8358         case 4:
8359           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8360           break;
8361         case 8:
8362           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8363           break;
8364         default:
8365           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8366         }
8367         if (cell >= 0) break;
8368       }
8369       break;
8370     default:
8371       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8372     }
8373     cells[p] = cell;
8374   }
8375   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8376   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8377   PetscFunctionReturn(0);
8378 }
8379 
8380 /******************************** FEM Support **********************************/
8381 
8382 #undef __FUNCT__
8383 #define __FUNCT__ "DMPlexVecGetClosure"
8384 /*@C
8385   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8386 
8387   Not collective
8388 
8389   Input Parameters:
8390 + dm - The DM
8391 . section - The section describing the layout in v, or NULL to use the default section
8392 . v - The local vector
8393 - point - The sieve point in the DM
8394 
8395   Output Parameters:
8396 + csize - The number of values in the closure, or NULL
8397 - values - The array of values, which is a borrowed array and should not be freed
8398 
8399   Level: intermediate
8400 
8401 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8402 @*/
8403 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8404 {
8405   PetscScalar   *array, *vArray;
8406   PetscInt      *points = NULL;
8407   PetscInt       offsets[32];
8408   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8409   PetscErrorCode ierr;
8410 
8411   PetscFunctionBegin;
8412   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8413   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8414   if (!section) {
8415     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8416   }
8417   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8418   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8419   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8420   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8421   /* Compress out points not in the section */
8422   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8423   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8424     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8425       points[q*2]   = points[p];
8426       points[q*2+1] = points[p+1];
8427       ++q;
8428     }
8429   }
8430   numPoints = q;
8431   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8432     PetscInt dof, fdof;
8433 
8434     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8435     for (f = 0; f < numFields; ++f) {
8436       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8437       offsets[f+1] += fdof;
8438     }
8439     size += dof;
8440   }
8441   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8442   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8443   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8444   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8445   for (p = 0; p < numPoints*2; p += 2) {
8446     PetscInt     o = points[p+1];
8447     PetscInt     dof, off, d;
8448     PetscScalar *varr;
8449 
8450     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8451     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8452     varr = &vArray[off];
8453     if (numFields) {
8454       PetscInt fdof, foff, fcomp, f, c;
8455 
8456       for (f = 0, foff = 0; f < numFields; ++f) {
8457         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8458         if (o >= 0) {
8459           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8460             array[offsets[f]] = varr[foff+d];
8461           }
8462         } else {
8463           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8464           for (d = fdof/fcomp-1; d >= 0; --d) {
8465             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8466               array[offsets[f]] = varr[foff+d*fcomp+c];
8467             }
8468           }
8469         }
8470         foff += fdof;
8471       }
8472     } else {
8473       if (o >= 0) {
8474         for (d = 0; d < dof; ++d, ++offsets[0]) {
8475           array[offsets[0]] = varr[d];
8476         }
8477       } else {
8478         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8479           array[offsets[0]] = varr[d];
8480         }
8481       }
8482     }
8483   }
8484   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8485   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8486   if (csize) *csize = size;
8487   *values = array;
8488   PetscFunctionReturn(0);
8489 }
8490 
8491 #undef __FUNCT__
8492 #define __FUNCT__ "DMPlexVecRestoreClosure"
8493 /*@C
8494   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8495 
8496   Not collective
8497 
8498   Input Parameters:
8499 + dm - The DM
8500 . section - The section describing the layout in v, or NULL to use the default section
8501 . v - The local vector
8502 . point - The sieve point in the DM
8503 . csize - The number of values in the closure, or NULL
8504 - values - The array of values, which is a borrowed array and should not be freed
8505 
8506   Level: intermediate
8507 
8508 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8509 @*/
8510 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8511 {
8512   PetscInt       size = 0;
8513   PetscErrorCode ierr;
8514 
8515   PetscFunctionBegin;
8516   /* Should work without recalculating size */
8517   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8518   PetscFunctionReturn(0);
8519 }
8520 
8521 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8522 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8523 
8524 #undef __FUNCT__
8525 #define __FUNCT__ "updatePoint_private"
8526 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8527 {
8528   PetscInt        cdof;   /* The number of constraints on this point */
8529   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8530   PetscScalar    *a;
8531   PetscInt        off, cind = 0, k;
8532   PetscErrorCode  ierr;
8533 
8534   PetscFunctionBegin;
8535   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8536   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8537   a    = &array[off];
8538   if (!cdof || setBC) {
8539     if (orientation >= 0) {
8540       for (k = 0; k < dof; ++k) {
8541         fuse(&a[k], values[k]);
8542       }
8543     } else {
8544       for (k = 0; k < dof; ++k) {
8545         fuse(&a[k], values[dof-k-1]);
8546       }
8547     }
8548   } else {
8549     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8550     if (orientation >= 0) {
8551       for (k = 0; k < dof; ++k) {
8552         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8553         fuse(&a[k], values[k]);
8554       }
8555     } else {
8556       for (k = 0; k < dof; ++k) {
8557         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8558         fuse(&a[k], values[dof-k-1]);
8559       }
8560     }
8561   }
8562   PetscFunctionReturn(0);
8563 }
8564 
8565 #undef __FUNCT__
8566 #define __FUNCT__ "updatePointFields_private"
8567 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8568 {
8569   PetscScalar   *a;
8570   PetscInt       numFields, off, foff, f;
8571   PetscErrorCode ierr;
8572 
8573   PetscFunctionBegin;
8574   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8575   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8576   a    = &array[off];
8577   for (f = 0, foff = 0; f < numFields; ++f) {
8578     PetscInt        fdof, fcomp, fcdof;
8579     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8580     PetscInt        cind = 0, k, c;
8581 
8582     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8583     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8584     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8585     if (!fcdof || setBC) {
8586       if (orientation >= 0) {
8587         for (k = 0; k < fdof; ++k) {
8588           fuse(&a[foff+k], values[foffs[f]+k]);
8589         }
8590       } else {
8591         for (k = fdof/fcomp-1; k >= 0; --k) {
8592           for (c = 0; c < fcomp; ++c) {
8593             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8594           }
8595         }
8596       }
8597     } else {
8598       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8599       if (orientation >= 0) {
8600         for (k = 0; k < fdof; ++k) {
8601           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8602           fuse(&a[foff+k], values[foffs[f]+k]);
8603         }
8604       } else {
8605         for (k = fdof/fcomp-1; k >= 0; --k) {
8606           for (c = 0; c < fcomp; ++c) {
8607             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8608             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8609           }
8610         }
8611       }
8612     }
8613     foff     += fdof;
8614     foffs[f] += fdof;
8615   }
8616   PetscFunctionReturn(0);
8617 }
8618 
8619 #undef __FUNCT__
8620 #define __FUNCT__ "DMPlexVecSetClosure"
8621 /*@C
8622   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8623 
8624   Not collective
8625 
8626   Input Parameters:
8627 + dm - The DM
8628 . section - The section describing the layout in v, or NULL to use the default sectionw
8629 . v - The local vector
8630 . point - The sieve point in the DM
8631 . values - The array of values, which is a borrowed array and should not be freed
8632 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8633 
8634   Level: intermediate
8635 
8636 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8637 @*/
8638 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8639 {
8640   PetscScalar   *array;
8641   PetscInt      *points = NULL;
8642   PetscInt       offsets[32];
8643   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8644   PetscErrorCode ierr;
8645 
8646   PetscFunctionBegin;
8647   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8648   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8649   if (!section) {
8650     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8651   }
8652   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8653   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8654   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8655   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8656   /* Compress out points not in the section */
8657   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8658   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8659     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8660       points[q*2]   = points[p];
8661       points[q*2+1] = points[p+1];
8662       ++q;
8663     }
8664   }
8665   numPoints = q;
8666   for (p = 0; p < numPoints*2; p += 2) {
8667     PetscInt fdof;
8668 
8669     for (f = 0; f < numFields; ++f) {
8670       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8671       offsets[f+1] += fdof;
8672     }
8673   }
8674   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8675   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8676   if (numFields) {
8677     switch (mode) {
8678     case INSERT_VALUES:
8679       for (p = 0; p < numPoints*2; p += 2) {
8680         PetscInt o = points[p+1];
8681         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8682       } break;
8683     case INSERT_ALL_VALUES:
8684       for (p = 0; p < numPoints*2; p += 2) {
8685         PetscInt o = points[p+1];
8686         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8687       } break;
8688     case ADD_VALUES:
8689       for (p = 0; p < numPoints*2; p += 2) {
8690         PetscInt o = points[p+1];
8691         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8692       } break;
8693     case ADD_ALL_VALUES:
8694       for (p = 0; p < numPoints*2; p += 2) {
8695         PetscInt o = points[p+1];
8696         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8697       } break;
8698     default:
8699       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8700     }
8701   } else {
8702     switch (mode) {
8703     case INSERT_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, insert, PETSC_FALSE, o, &values[off], array);
8708       } break;
8709     case INSERT_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, insert, PETSC_TRUE,  o, &values[off], array);
8714       } break;
8715     case ADD_VALUES:
8716       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8717         PetscInt o = points[p+1];
8718         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8719         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8720       } break;
8721     case ADD_ALL_VALUES:
8722       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8723         PetscInt o = points[p+1];
8724         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8725         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8726       } break;
8727     default:
8728       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8729     }
8730   }
8731   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8732   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8733   PetscFunctionReturn(0);
8734 }
8735 
8736 #undef __FUNCT__
8737 #define __FUNCT__ "DMPlexPrintMatSetValues"
8738 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8739 {
8740   PetscMPIInt    rank;
8741   PetscInt       i, j;
8742   PetscErrorCode ierr;
8743 
8744   PetscFunctionBegin;
8745   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
8746   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8747   for (i = 0; i < numIndices; i++) {
8748     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8749   }
8750   for (i = 0; i < numIndices; i++) {
8751     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8752     for (j = 0; j < numIndices; j++) {
8753 #if defined(PETSC_USE_COMPLEX)
8754       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8755 #else
8756       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8757 #endif
8758     }
8759     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8760   }
8761   PetscFunctionReturn(0);
8762 }
8763 
8764 #undef __FUNCT__
8765 #define __FUNCT__ "indicesPoint_private"
8766 /* . off - The global offset of this point */
8767 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8768 {
8769   PetscInt        dof;    /* The number of unknowns on this point */
8770   PetscInt        cdof;   /* The number of constraints on this point */
8771   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8772   PetscInt        cind = 0, k;
8773   PetscErrorCode  ierr;
8774 
8775   PetscFunctionBegin;
8776   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8777   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8778   if (!cdof || setBC) {
8779     if (orientation >= 0) {
8780       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8781     } else {
8782       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8783     }
8784   } else {
8785     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8786     if (orientation >= 0) {
8787       for (k = 0; k < dof; ++k) {
8788         if ((cind < cdof) && (k == cdofs[cind])) {
8789           /* Insert check for returning constrained indices */
8790           indices[*loff+k] = -(off+k+1);
8791           ++cind;
8792         } else {
8793           indices[*loff+k] = off+k-cind;
8794         }
8795       }
8796     } else {
8797       for (k = 0; k < dof; ++k) {
8798         if ((cind < cdof) && (k == cdofs[cind])) {
8799           /* Insert check for returning constrained indices */
8800           indices[*loff+dof-k-1] = -(off+k+1);
8801           ++cind;
8802         } else {
8803           indices[*loff+dof-k-1] = off+k-cind;
8804         }
8805       }
8806     }
8807   }
8808   *loff += dof;
8809   PetscFunctionReturn(0);
8810 }
8811 
8812 #undef __FUNCT__
8813 #define __FUNCT__ "indicesPointFields_private"
8814 /* . off - The global offset of this point */
8815 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8816 {
8817   PetscInt       numFields, foff, f;
8818   PetscErrorCode ierr;
8819 
8820   PetscFunctionBegin;
8821   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8822   for (f = 0, foff = 0; f < numFields; ++f) {
8823     PetscInt        fdof, fcomp, cfdof;
8824     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8825     PetscInt        cind = 0, k, c;
8826 
8827     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8828     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8829     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8830     if (!cfdof || setBC) {
8831       if (orientation >= 0) {
8832         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8833       } else {
8834         for (k = fdof/fcomp-1; k >= 0; --k) {
8835           for (c = 0; c < fcomp; ++c) {
8836             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8837           }
8838         }
8839       }
8840     } else {
8841       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8842       if (orientation >= 0) {
8843         for (k = 0; k < fdof; ++k) {
8844           if ((cind < cfdof) && (k == fcdofs[cind])) {
8845             indices[foffs[f]+k] = -(off+foff+k+1);
8846             ++cind;
8847           } else {
8848             indices[foffs[f]+k] = off+foff+k-cind;
8849           }
8850         }
8851       } else {
8852         for (k = fdof/fcomp-1; k >= 0; --k) {
8853           for (c = 0; c < fcomp; ++c) {
8854             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8855               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8856               ++cind;
8857             } else {
8858               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8859             }
8860           }
8861         }
8862       }
8863     }
8864     foff     += fdof - cfdof;
8865     foffs[f] += fdof;
8866   }
8867   PetscFunctionReturn(0);
8868 }
8869 
8870 #undef __FUNCT__
8871 #define __FUNCT__ "DMPlexMatSetClosure"
8872 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8873 {
8874   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8875   PetscInt      *points = NULL;
8876   PetscInt      *indices;
8877   PetscInt       offsets[32];
8878   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8879   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8880   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8881   PetscErrorCode ierr;
8882 
8883   PetscFunctionBegin;
8884   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8885   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8886   if (useDefault) {
8887     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8888   }
8889   if (useGlobalDefault) {
8890     if (useDefault) {
8891       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8892     } else {
8893       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8894     }
8895   }
8896   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8897   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8898   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8899   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8900   /* Compress out points not in the section */
8901   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8902   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8903     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8904       points[q*2]   = points[p];
8905       points[q*2+1] = points[p+1];
8906       ++q;
8907     }
8908   }
8909   numPoints = q;
8910   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8911     PetscInt fdof;
8912 
8913     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8914     for (f = 0; f < numFields; ++f) {
8915       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8916       offsets[f+1] += fdof;
8917     }
8918     numIndices += dof;
8919   }
8920   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8921 
8922   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8923   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8924   if (numFields) {
8925     for (p = 0; p < numPoints*2; p += 2) {
8926       PetscInt o = points[p+1];
8927       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8928       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8929     }
8930   } else {
8931     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8932       PetscInt o = points[p+1];
8933       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8934       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8935     }
8936   }
8937   if (useGlobalDefault && !useDefault) {
8938     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8939   }
8940   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8941   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8942   if (ierr) {
8943     PetscMPIInt    rank;
8944     PetscErrorCode ierr2;
8945 
8946     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
8947     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8948     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8949     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8950     CHKERRQ(ierr);
8951   }
8952   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8953   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8954   PetscFunctionReturn(0);
8955 }
8956 
8957 #undef __FUNCT__
8958 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8959 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8960 {
8961   PetscSection       coordSection;
8962   Vec                coordinates;
8963   const PetscScalar *coords;
8964   const PetscInt     dim = 2;
8965   PetscInt           d, f;
8966   PetscErrorCode     ierr;
8967 
8968   PetscFunctionBegin;
8969   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8970   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8971   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8972   if (v0) {
8973     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8974   }
8975   if (J) {
8976     for (d = 0; d < dim; d++) {
8977       for (f = 0; f < dim; f++) {
8978         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8979       }
8980     }
8981     *detJ = J[0]*J[3] - J[1]*J[2];
8982 #if 0
8983     if (detJ < 0.0) {
8984       const PetscReal xLength = mesh->periodicity[0];
8985 
8986       if (xLength != 0.0) {
8987         PetscReal v0x = coords[0*dim+0];
8988 
8989         if (v0x == 0.0) v0x = v0[0] = xLength;
8990         for (f = 0; f < dim; f++) {
8991           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8992 
8993           J[0*dim+f] = 0.5*(px - v0x);
8994         }
8995       }
8996       detJ = J[0]*J[3] - J[1]*J[2];
8997     }
8998 #endif
8999     PetscLogFlops(8.0 + 3.0);
9000   }
9001   if (invJ) {
9002     const PetscReal invDet = 1.0/(*detJ);
9003 
9004     invJ[0] =  invDet*J[3];
9005     invJ[1] = -invDet*J[1];
9006     invJ[2] = -invDet*J[2];
9007     invJ[3] =  invDet*J[0];
9008     PetscLogFlops(5.0);
9009   }
9010   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9011   PetscFunctionReturn(0);
9012 }
9013 
9014 #undef __FUNCT__
9015 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9016 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9017 {
9018   PetscSection       coordSection;
9019   Vec                coordinates;
9020   const PetscScalar *coords;
9021   const PetscInt     dim = 2;
9022   PetscInt           d, f;
9023   PetscErrorCode     ierr;
9024 
9025   PetscFunctionBegin;
9026   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9027   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9028   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9029   if (v0) {
9030     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9031   }
9032   if (J) {
9033     for (d = 0; d < dim; d++) {
9034       for (f = 0; f < dim; f++) {
9035         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9036       }
9037     }
9038     *detJ = J[0]*J[3] - J[1]*J[2];
9039     PetscLogFlops(8.0 + 3.0);
9040   }
9041   if (invJ) {
9042     const PetscReal invDet = 1.0/(*detJ);
9043 
9044     invJ[0] =  invDet*J[3];
9045     invJ[1] = -invDet*J[1];
9046     invJ[2] = -invDet*J[2];
9047     invJ[3] =  invDet*J[0];
9048     PetscLogFlops(5.0);
9049   }
9050   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9051   PetscFunctionReturn(0);
9052 }
9053 
9054 #undef __FUNCT__
9055 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9056 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9057 {
9058   PetscSection       coordSection;
9059   Vec                coordinates;
9060   const PetscScalar *coords;
9061   const PetscInt     dim = 3;
9062   PetscInt           d, f;
9063   PetscErrorCode     ierr;
9064 
9065   PetscFunctionBegin;
9066   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9067   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9068   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9069   if (v0) {
9070     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9071   }
9072   if (J) {
9073     for (d = 0; d < dim; d++) {
9074       for (f = 0; f < dim; f++) {
9075         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9076       }
9077     }
9078     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9079     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9080              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9081              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9082     PetscLogFlops(18.0 + 12.0);
9083   }
9084   if (invJ) {
9085     const PetscReal invDet = 1.0/(*detJ);
9086 
9087     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9088     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9089     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9090     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9091     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9092     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9093     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9094     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9095     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9096     PetscLogFlops(37.0);
9097   }
9098   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9099   PetscFunctionReturn(0);
9100 }
9101 
9102 #undef __FUNCT__
9103 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9104 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9105 {
9106   PetscSection       coordSection;
9107   Vec                coordinates;
9108   const PetscScalar *coords;
9109   const PetscInt     dim = 3;
9110   PetscInt           d;
9111   PetscErrorCode     ierr;
9112 
9113   PetscFunctionBegin;
9114   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9115   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9116   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9117   if (v0) {
9118     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9119   }
9120   if (J) {
9121     for (d = 0; d < dim; d++) {
9122       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9123       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9124       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9125     }
9126     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9127              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9128              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9129     PetscLogFlops(18.0 + 12.0);
9130   }
9131   if (invJ) {
9132     const PetscReal invDet = -1.0/(*detJ);
9133 
9134     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9135     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9136     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9137     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9138     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9139     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9140     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9141     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9142     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9143     PetscLogFlops(37.0);
9144   }
9145   *detJ *= 8.0;
9146   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9147   PetscFunctionReturn(0);
9148 }
9149 
9150 #undef __FUNCT__
9151 #define __FUNCT__ "DMPlexComputeCellGeometry"
9152 /*@C
9153   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9154 
9155   Collective on DM
9156 
9157   Input Arguments:
9158 + dm   - the DM
9159 - cell - the cell
9160 
9161   Output Arguments:
9162 + v0   - the translation part of this affine transform
9163 . J    - the Jacobian of the transform to the reference element
9164 . invJ - the inverse of the Jacobian
9165 - detJ - the Jacobian determinant
9166 
9167   Level: advanced
9168 
9169 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9170 @*/
9171 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9172 {
9173   PetscInt       dim, coneSize;
9174   PetscErrorCode ierr;
9175 
9176   PetscFunctionBegin;
9177   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9178   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9179   switch (dim) {
9180   case 2:
9181     switch (coneSize) {
9182     case 3:
9183       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9184       break;
9185     case 4:
9186       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9187       break;
9188     default:
9189       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9190     }
9191     break;
9192   case 3:
9193     switch (coneSize) {
9194     case 4:
9195       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9196       break;
9197     case 8:
9198       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9199       break;
9200     default:
9201       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9202     }
9203     break;
9204   default:
9205     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9206   }
9207   PetscFunctionReturn(0);
9208 }
9209 
9210 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9211 {
9212   switch (i) {
9213   case 0:
9214     switch (j) {
9215     case 0: return 0;
9216     case 1:
9217       switch (k) {
9218       case 0: return 0;
9219       case 1: return 0;
9220       case 2: return 1;
9221       }
9222     case 2:
9223       switch (k) {
9224       case 0: return 0;
9225       case 1: return -1;
9226       case 2: return 0;
9227       }
9228     }
9229   case 1:
9230     switch (j) {
9231     case 0:
9232       switch (k) {
9233       case 0: return 0;
9234       case 1: return 0;
9235       case 2: return -1;
9236       }
9237     case 1: return 0;
9238     case 2:
9239       switch (k) {
9240       case 0: return 1;
9241       case 1: return 0;
9242       case 2: return 0;
9243       }
9244     }
9245   case 2:
9246     switch (j) {
9247     case 0:
9248       switch (k) {
9249       case 0: return 0;
9250       case 1: return 1;
9251       case 2: return 0;
9252       }
9253     case 1:
9254       switch (k) {
9255       case 0: return -1;
9256       case 1: return 0;
9257       case 2: return 0;
9258       }
9259     case 2: return 0;
9260     }
9261   }
9262   return 0;
9263 }
9264 
9265 #undef __FUNCT__
9266 #define __FUNCT__ "DMPlexCreateRigidBody"
9267 /*@C
9268   DMPlexCreateRigidBody - create rigid body modes from coordinates
9269 
9270   Collective on DM
9271 
9272   Input Arguments:
9273 + dm - the DM
9274 . section - the local section associated with the rigid field, or NULL for the default section
9275 - globalSection - the global section associated with the rigid field, or NULL for the default section
9276 
9277   Output Argument:
9278 . sp - the null space
9279 
9280   Note: This is necessary to take account of Dirichlet conditions on the displacements
9281 
9282   Level: advanced
9283 
9284 .seealso: MatNullSpaceCreate()
9285 @*/
9286 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9287 {
9288   MPI_Comm       comm;
9289   Vec            coordinates, localMode, mode[6];
9290   PetscSection   coordSection;
9291   PetscScalar   *coords;
9292   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9293   PetscErrorCode ierr;
9294 
9295   PetscFunctionBegin;
9296   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
9297   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9298   if (dim == 1) {
9299     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
9300     PetscFunctionReturn(0);
9301   }
9302   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9303   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9304   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9305   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9306   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9307   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9308   m    = (dim*(dim+1))/2;
9309   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9310   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9311   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9312   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9313   /* Assume P1 */
9314   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9315   for (d = 0; d < dim; ++d) {
9316     PetscScalar values[3] = {0.0, 0.0, 0.0};
9317 
9318     values[d] = 1.0;
9319     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
9320     for (v = vStart; v < vEnd; ++v) {
9321       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9322     }
9323     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9324     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9325   }
9326   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9327   for (d = dim; d < dim*(dim+1)/2; ++d) {
9328     PetscInt i, j, k = dim > 2 ? d - dim : d;
9329 
9330     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9331     for (v = vStart; v < vEnd; ++v) {
9332       PetscScalar values[3] = {0.0, 0.0, 0.0};
9333       PetscInt    off;
9334 
9335       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9336       for (i = 0; i < dim; ++i) {
9337         for (j = 0; j < dim; ++j) {
9338           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9339         }
9340       }
9341       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9342     }
9343     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9344     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9345   }
9346   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9347   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9348   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
9349   /* Orthonormalize system */
9350   for (i = dim; i < m; ++i) {
9351     PetscScalar dots[6];
9352 
9353     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9354     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9355     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9356     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
9357   }
9358   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9359   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9360   PetscFunctionReturn(0);
9361 }
9362 
9363 #undef __FUNCT__
9364 #define __FUNCT__ "DMPlexGetHybridBounds"
9365 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9366 {
9367   DM_Plex       *mesh = (DM_Plex*) dm->data;
9368   PetscInt       dim;
9369   PetscErrorCode ierr;
9370 
9371   PetscFunctionBegin;
9372   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9373   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9374   if (cMax) *cMax = mesh->hybridPointMax[dim];
9375   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9376   if (eMax) *eMax = mesh->hybridPointMax[1];
9377   if (vMax) *vMax = mesh->hybridPointMax[0];
9378   PetscFunctionReturn(0);
9379 }
9380 
9381 #undef __FUNCT__
9382 #define __FUNCT__ "DMPlexSetHybridBounds"
9383 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9384 {
9385   DM_Plex       *mesh = (DM_Plex*) dm->data;
9386   PetscInt       dim;
9387   PetscErrorCode ierr;
9388 
9389   PetscFunctionBegin;
9390   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9391   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9392   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9393   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9394   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9395   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9396   PetscFunctionReturn(0);
9397 }
9398 
9399 #undef __FUNCT__
9400 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9401 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9402 {
9403   DM_Plex *mesh = (DM_Plex*) dm->data;
9404 
9405   PetscFunctionBegin;
9406   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9407   PetscValidPointer(cellHeight, 2);
9408   *cellHeight = mesh->vtkCellHeight;
9409   PetscFunctionReturn(0);
9410 }
9411 
9412 #undef __FUNCT__
9413 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9414 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9415 {
9416   DM_Plex *mesh = (DM_Plex*) dm->data;
9417 
9418   PetscFunctionBegin;
9419   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9420   mesh->vtkCellHeight = cellHeight;
9421   PetscFunctionReturn(0);
9422 }
9423 
9424 #undef __FUNCT__
9425 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9426 /* We can easily have a form that takes an IS instead */
9427 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9428 {
9429   PetscSection   section, globalSection;
9430   PetscInt      *numbers, p;
9431   PetscErrorCode ierr;
9432 
9433   PetscFunctionBegin;
9434   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
9435   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9436   for (p = pStart; p < pEnd; ++p) {
9437     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9438   }
9439   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9440   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9441   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9442   for (p = pStart; p < pEnd; ++p) {
9443     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9444   }
9445   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9446   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9447   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9448   PetscFunctionReturn(0);
9449 }
9450 
9451 #undef __FUNCT__
9452 #define __FUNCT__ "DMPlexGetCellNumbering"
9453 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9454 {
9455   DM_Plex       *mesh = (DM_Plex*) dm->data;
9456   PetscInt       cellHeight, cStart, cEnd, cMax;
9457   PetscErrorCode ierr;
9458 
9459   PetscFunctionBegin;
9460   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9461   if (!mesh->globalCellNumbers) {
9462     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9463     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9464     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
9465     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9466     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9467   }
9468   *globalCellNumbers = mesh->globalCellNumbers;
9469   PetscFunctionReturn(0);
9470 }
9471 
9472 #undef __FUNCT__
9473 #define __FUNCT__ "DMPlexGetVertexNumbering"
9474 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9475 {
9476   DM_Plex       *mesh = (DM_Plex*) dm->data;
9477   PetscInt       vStart, vEnd, vMax;
9478   PetscErrorCode ierr;
9479 
9480   PetscFunctionBegin;
9481   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9482   if (!mesh->globalVertexNumbers) {
9483     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9484     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
9485     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9486     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9487   }
9488   *globalVertexNumbers = mesh->globalVertexNumbers;
9489   PetscFunctionReturn(0);
9490 }
9491 
9492 #undef __FUNCT__
9493 #define __FUNCT__ "DMPlexGetScale"
9494 PetscErrorCode DMPlexGetScale(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   PetscValidPointer(scale, 3);
9501   *scale = mesh->scale[unit];
9502   PetscFunctionReturn(0);
9503 }
9504 
9505 #undef __FUNCT__
9506 #define __FUNCT__ "DMPlexSetScale"
9507 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9508 {
9509   DM_Plex *mesh = (DM_Plex*) dm->data;
9510 
9511   PetscFunctionBegin;
9512   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9513   mesh->scale[unit] = scale;
9514   PetscFunctionReturn(0);
9515 }
9516 
9517 
9518 /*******************************************************************************
9519 This should be in a separate Discretization object, but I am not sure how to lay
9520 it out yet, so I am stuffing things here while I experiment.
9521 *******************************************************************************/
9522 #undef __FUNCT__
9523 #define __FUNCT__ "DMPlexSetFEMIntegration"
9524 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9525                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9526                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9527                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9528                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9529                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9530                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9531                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9532                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9533                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9534                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9535                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9536                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9537                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9538                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9539                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9540                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9541 {
9542   DM_Plex *mesh = (DM_Plex*) dm->data;
9543 
9544   PetscFunctionBegin;
9545   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9546   mesh->integrateResidualFEM       = integrateResidualFEM;
9547   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9548   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9549   PetscFunctionReturn(0);
9550 }
9551 
9552 #undef __FUNCT__
9553 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9554 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9555 {
9556   Vec            coordinates;
9557   PetscSection   section, cSection;
9558   PetscInt       dim, vStart, vEnd, v, c, d;
9559   PetscScalar   *values, *cArray;
9560   PetscReal     *coords;
9561   PetscErrorCode ierr;
9562 
9563   PetscFunctionBegin;
9564   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9565   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9566   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9567   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9568   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9569   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9570   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9571   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9572   for (v = vStart; v < vEnd; ++v) {
9573     PetscInt dof, off;
9574 
9575     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9576     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9577     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9578     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9579     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9580     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9581   }
9582   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9583   /* Temporary, must be replaced by a projection on the finite element basis */
9584   {
9585     PetscInt eStart = 0, eEnd = 0, e, depth;
9586 
9587     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9588     --depth;
9589     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9590     for (e = eStart; e < eEnd; ++e) {
9591       const PetscInt *cone = NULL;
9592       PetscInt        coneSize, d;
9593       PetscScalar    *coordsA, *coordsB;
9594 
9595       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9596       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9597       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9598       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9599       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9600       for (d = 0; d < dim; ++d) {
9601         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9602       }
9603       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9604       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9605     }
9606   }
9607 
9608   ierr = PetscFree(coords);CHKERRQ(ierr);
9609   ierr = PetscFree(values);CHKERRQ(ierr);
9610 #if 0
9611   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9612   PetscReal      detJ;
9613 
9614   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9615   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9616   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9617 
9618   for (PetscInt c = cStart; c < cEnd; ++c) {
9619     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9620     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9621     const int                          oSize   = pV.getSize();
9622     int                                v       = 0;
9623 
9624     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9625     for (PetscInt cl = 0; cl < oSize; ++cl) {
9626       const PetscInt fDim;
9627 
9628       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9629       if (pointDim) {
9630         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9631           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9632         }
9633       }
9634     }
9635     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9636     pV.clear();
9637   }
9638   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9639   ierr = PetscFree(values);CHKERRQ(ierr);
9640 #endif
9641   PetscFunctionReturn(0);
9642 }
9643 
9644 #undef __FUNCT__
9645 #define __FUNCT__ "DMPlexProjectFunction"
9646 /*@C
9647   DMPlexProjectFunction - This projects the given function into the function space provided.
9648 
9649   Input Parameters:
9650 + dm      - The DM
9651 . numComp - The number of components (functions)
9652 . funcs   - The coordinate functions to evaluate
9653 - mode    - The insertion mode for values
9654 
9655   Output Parameter:
9656 . X - vector
9657 
9658   Level: developer
9659 
9660   Note:
9661   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9662   We will eventually fix it.
9663 
9664 ,seealso: DMPlexComputeL2Diff()
9665 */
9666 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9667 {
9668   Vec            localX;
9669   PetscErrorCode ierr;
9670 
9671   PetscFunctionBegin;
9672   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9673   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9674   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9675   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9676   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9677   PetscFunctionReturn(0);
9678 }
9679 
9680 #undef __FUNCT__
9681 #define __FUNCT__ "DMPlexComputeL2Diff"
9682 /*@C
9683   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9684 
9685   Input Parameters:
9686 + dm    - The DM
9687 . quad  - The PetscQuadrature object for each field
9688 . funcs - The functions to evaluate for each field component
9689 - X     - The coefficient vector u_h
9690 
9691   Output Parameter:
9692 . diff - The diff ||u - u_h||_2
9693 
9694   Level: developer
9695 
9696 .seealso: DMPlexProjectFunction()
9697 */
9698 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9699 {
9700   const PetscInt debug = 0;
9701   PetscSection   section;
9702   Vec            localX;
9703   PetscReal     *coords, *v0, *J, *invJ, detJ;
9704   PetscReal      localDiff = 0.0;
9705   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9706   PetscErrorCode ierr;
9707 
9708   PetscFunctionBegin;
9709   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9710   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9711   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9712   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9713   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9714   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9715   for (field = 0; field < numFields; ++field) {
9716     numComponents += quad[field].numComponents;
9717   }
9718   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9719   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9720   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9721   for (c = cStart; c < cEnd; ++c) {
9722     const PetscScalar *x;
9723     PetscReal          elemDiff = 0.0;
9724 
9725     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9726     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9727     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9728 
9729     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9730       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9731       const PetscReal *quadPoints    = quad[field].quadPoints;
9732       const PetscReal *quadWeights   = quad[field].quadWeights;
9733       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9734       const PetscInt   numBasisComps = quad[field].numComponents;
9735       const PetscReal *basis         = quad[field].basis;
9736       PetscInt         q, d, e, fc, f;
9737 
9738       if (debug) {
9739         char title[1024];
9740         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9741         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9742       }
9743       for (q = 0; q < numQuadPoints; ++q) {
9744         for (d = 0; d < dim; d++) {
9745           coords[d] = v0[d];
9746           for (e = 0; e < dim; e++) {
9747             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9748           }
9749         }
9750         for (fc = 0; fc < numBasisComps; ++fc) {
9751           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9752           PetscReal       interpolant = 0.0;
9753           for (f = 0; f < numBasisFuncs; ++f) {
9754             const PetscInt fidx = f*numBasisComps+fc;
9755             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9756           }
9757           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9758           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9759         }
9760       }
9761       comp        += numBasisComps;
9762       fieldOffset += numBasisFuncs*numBasisComps;
9763     }
9764     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9765     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9766     localDiff += elemDiff;
9767   }
9768   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9769   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9770   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9771   *diff = PetscSqrtReal(*diff);
9772   PetscFunctionReturn(0);
9773 }
9774 
9775 #undef __FUNCT__
9776 #define __FUNCT__ "DMPlexComputeResidualFEM"
9777 /*@
9778   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9779 
9780   Input Parameters:
9781 + dm - The mesh
9782 . X  - Local input vector
9783 - user - The user context
9784 
9785   Output Parameter:
9786 . F  - Local output vector
9787 
9788   Note:
9789   The second member of the user context must be an FEMContext.
9790 
9791   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9792   like a GPU, or vectorize on a multicore machine.
9793 
9794 .seealso: DMPlexComputeJacobianActionFEM()
9795 */
9796 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9797 {
9798   DM_Plex         *mesh = (DM_Plex*) dm->data;
9799   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9800   PetscQuadrature *quad = fem->quad;
9801   PetscSection     section;
9802   PetscReal       *v0, *J, *invJ, *detJ;
9803   PetscScalar     *elemVec, *u;
9804   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9805   PetscInt         cellDof = 0, numComponents = 0;
9806   PetscErrorCode   ierr;
9807 
9808   PetscFunctionBegin;
9809   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9810   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9811   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9812   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9813   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9814   numCells = cEnd - cStart;
9815   for (field = 0; field < numFields; ++field) {
9816     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9817     numComponents += quad[field].numComponents;
9818   }
9819   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9820   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9821   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);
9822   for (c = cStart; c < cEnd; ++c) {
9823     const PetscScalar *x;
9824     PetscInt           i;
9825 
9826     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9827     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9828     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9829 
9830     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9831     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9832   }
9833   for (field = 0; field < numFields; ++field) {
9834     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9835     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9836     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9837     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9838     /* Conforming batches */
9839     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9840     PetscInt numBlocks  = 1;
9841     PetscInt batchSize  = numBlocks * blockSize;
9842     PetscInt numBatches = numBatchesTmp;
9843     PetscInt numChunks  = numCells / (numBatches*batchSize);
9844     /* Remainder */
9845     PetscInt numRemainder = numCells % (numBatches * batchSize);
9846     PetscInt offset       = numCells - numRemainder;
9847 
9848     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9849     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9850                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9851   }
9852   for (c = cStart; c < cEnd; ++c) {
9853     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9854     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9855   }
9856   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9857   if (mesh->printFEM) {
9858     PetscMPIInt rank, numProcs;
9859     PetscInt    p;
9860 
9861     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9862     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9863     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9864     for (p = 0; p < numProcs; ++p) {
9865       if (p == rank) {
9866         Vec f;
9867 
9868         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9869         ierr = VecCopy(F, f);CHKERRQ(ierr);
9870         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9871         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9872         ierr = VecDestroy(&f);CHKERRQ(ierr);
9873         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9874       }
9875       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9876     }
9877   }
9878   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9879   PetscFunctionReturn(0);
9880 }
9881 
9882 #undef __FUNCT__
9883 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9884 /*@C
9885   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9886 
9887   Input Parameters:
9888 + dm - The mesh
9889 . J  - The Jacobian shell matrix
9890 . X  - Local input vector
9891 - user - The user context
9892 
9893   Output Parameter:
9894 . F  - Local output vector
9895 
9896   Note:
9897   The second member of the user context must be an FEMContext.
9898 
9899   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9900   like a GPU, or vectorize on a multicore machine.
9901 
9902 .seealso: DMPlexComputeResidualFEM()
9903 */
9904 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9905 {
9906   DM_Plex         *mesh = (DM_Plex*) dm->data;
9907   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9908   PetscQuadrature *quad = fem->quad;
9909   PetscSection     section;
9910   JacActionCtx    *jctx;
9911   PetscReal       *v0, *J, *invJ, *detJ;
9912   PetscScalar     *elemVec, *u, *a;
9913   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9914   PetscInt         cellDof = 0;
9915   PetscErrorCode   ierr;
9916 
9917   PetscFunctionBegin;
9918   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9919   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9920   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9921   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9922   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9923   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9924   numCells = cEnd - cStart;
9925   for (field = 0; field < numFields; ++field) {
9926     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9927   }
9928   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9929   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);
9930   for (c = cStart; c < cEnd; ++c) {
9931     const PetscScalar *x;
9932     PetscInt           i;
9933 
9934     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9935     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9936     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9937     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9938     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9939     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9940     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9941     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9942   }
9943   for (field = 0; field < numFields; ++field) {
9944     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9945     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9946     /* Conforming batches */
9947     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9948     PetscInt numBlocks  = 1;
9949     PetscInt batchSize  = numBlocks * blockSize;
9950     PetscInt numBatches = numBatchesTmp;
9951     PetscInt numChunks  = numCells / (numBatches*batchSize);
9952     /* Remainder */
9953     PetscInt numRemainder = numCells % (numBatches * batchSize);
9954     PetscInt offset       = numCells - numRemainder;
9955 
9956     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);
9957     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],
9958                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9959   }
9960   for (c = cStart; c < cEnd; ++c) {
9961     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9962     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9963   }
9964   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9965   if (mesh->printFEM) {
9966     PetscMPIInt rank, numProcs;
9967     PetscInt    p;
9968 
9969     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9970     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9971     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9972     for (p = 0; p < numProcs; ++p) {
9973       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9974       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9975     }
9976   }
9977   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9978   PetscFunctionReturn(0);
9979 }
9980 
9981 #undef __FUNCT__
9982 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9983 /*@
9984   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9985 
9986   Input Parameters:
9987 + dm - The mesh
9988 . X  - Local input vector
9989 - user - The user context
9990 
9991   Output Parameter:
9992 . Jac  - Jacobian matrix
9993 
9994   Note:
9995   The second member of the user context must be an FEMContext.
9996 
9997   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9998   like a GPU, or vectorize on a multicore machine.
9999 
10000 .seealso: FormFunctionLocal()
10001 */
10002 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10003 {
10004   DM_Plex         *mesh = (DM_Plex*) dm->data;
10005   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10006   PetscQuadrature *quad = fem->quad;
10007   PetscSection     section;
10008   PetscReal       *v0, *J, *invJ, *detJ;
10009   PetscScalar     *elemMat, *u;
10010   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10011   PetscInt         cellDof = 0, numComponents = 0;
10012   PetscBool        isShell;
10013   PetscErrorCode   ierr;
10014 
10015   PetscFunctionBegin;
10016   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10017   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10018   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10019   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10020   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10021   numCells = cEnd - cStart;
10022   for (field = 0; field < numFields; ++field) {
10023     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10024     numComponents += quad[field].numComponents;
10025   }
10026   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10027   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10028   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);
10029   for (c = cStart; c < cEnd; ++c) {
10030     const PetscScalar *x;
10031     PetscInt           i;
10032 
10033     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10034     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10035     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10036 
10037     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10038     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10039   }
10040   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10041   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10042     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10043     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10044     PetscInt       fieldJ;
10045 
10046     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10047       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10048       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10049       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10050       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10051       /* Conforming batches */
10052       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10053       PetscInt numBlocks  = 1;
10054       PetscInt batchSize  = numBlocks * blockSize;
10055       PetscInt numBatches = numBatchesTmp;
10056       PetscInt numChunks  = numCells / (numBatches*batchSize);
10057       /* Remainder */
10058       PetscInt numRemainder = numCells % (numBatches * batchSize);
10059       PetscInt offset       = numCells - numRemainder;
10060 
10061       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10062       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10063                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10064     }
10065   }
10066   for (c = cStart; c < cEnd; ++c) {
10067     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10068     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10069   }
10070   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10071 
10072   /* Assemble matrix, using the 2-step process:
10073        MatAssemblyBegin(), MatAssemblyEnd(). */
10074   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10075   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10076 
10077   if (mesh->printFEM) {
10078     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10079     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10080     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10081   }
10082   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10083   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10084   if (isShell) {
10085     JacActionCtx *jctx;
10086 
10087     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10088     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10089   }
10090   *str = SAME_NONZERO_PATTERN;
10091   PetscFunctionReturn(0);
10092 }
10093 
10094 
10095 #undef __FUNCT__
10096 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10097 /*@C
10098   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10099   the local section and an SF describing the section point overlap.
10100 
10101   Input Parameters:
10102   + s - The PetscSection for the local field layout
10103   . sf - The SF describing parallel layout of the section points
10104   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10105   . label - The label specifying the points
10106   - labelValue - The label stratum specifying the points
10107 
10108   Output Parameter:
10109   . gsection - The PetscSection for the global field layout
10110 
10111   Note: This gives negative sizes and offsets to points not owned by this process
10112 
10113   Level: developer
10114 
10115 .seealso: PetscSectionCreate()
10116 @*/
10117 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10118 {
10119   PetscInt      *neg;
10120   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10121   PetscErrorCode ierr;
10122 
10123   PetscFunctionBegin;
10124   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10125   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10126   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10127   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10128   /* Mark ghost points with negative dof */
10129   for (p = pStart; p < pEnd; ++p) {
10130     PetscInt value;
10131 
10132     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
10133     if (value != labelValue) continue;
10134     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
10135     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
10136     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
10137     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
10138     neg[p-pStart] = -(dof+1);
10139   }
10140   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
10141   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
10142   if (nroots >= 0) {
10143     if (nroots > pEnd - pStart) {
10144       PetscInt *tmpDof;
10145       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10146       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
10147       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10148       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10149       for (p = pStart; p < pEnd; ++p) {
10150         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
10151       }
10152       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
10153     } else {
10154       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10155       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10156     }
10157   }
10158   /* Calculate new sizes, get proccess offset, and calculate point offsets */
10159   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10160     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
10161 
10162     (*gsection)->atlasOff[p] = off;
10163 
10164     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
10165   }
10166   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
10167   globalOff -= off;
10168   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10169     (*gsection)->atlasOff[p] += globalOff;
10170 
10171     neg[p] = -((*gsection)->atlasOff[p]+1);
10172   }
10173   /* Put in negative offsets for ghost points */
10174   if (nroots >= 0) {
10175     if (nroots > pEnd - pStart) {
10176       PetscInt *tmpOff;
10177       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10178       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
10179       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10180       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10181       for (p = pStart; p < pEnd; ++p) {
10182         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
10183       }
10184       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
10185     } else {
10186       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10187       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10188     }
10189   }
10190   ierr = PetscFree(neg);CHKERRQ(ierr);
10191   PetscFunctionReturn(0);
10192 }
10193