xref: /petsc/src/dm/impls/plex/plex.c (revision 879dac06bebc0af1fa2f195c25f9eb0f1d82d9c7)
1 #include <petsc-private/pleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 
4 /* Logging support */
5 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
6 
7 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
8 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "VecView_Plex_Local"
12 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
13 {
14   DM             dm;
15   PetscBool      isvtk;
16   PetscErrorCode ierr;
17 
18   PetscFunctionBegin;
19   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
20   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
21   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
22   if (isvtk) {
23     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
24     PetscSection            section;
25     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
26 
27     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
28     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
29     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
30     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, PETSC_NULL);CHKERRQ(ierr);
31     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, PETSC_NULL);CHKERRQ(ierr);
32     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
33     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
34     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
35     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
36     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
37     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
38       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
39     } else if (cdof && vdof) {
40       SETERRQ(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
41     } else if (cdof) {
42       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
43        * vector or just happens to have the same number of dofs as the dimension. */
44       if (cdof == dim) {
45         ft = PETSC_VTK_CELL_VECTOR_FIELD;
46       } else {
47         ft = PETSC_VTK_CELL_FIELD;
48       }
49     } else if (vdof) {
50       if (vdof == dim) {
51         ft = PETSC_VTK_POINT_VECTOR_FIELD;
52       } else {
53         ft = PETSC_VTK_POINT_FIELD;
54       }
55     } else SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
56 
57     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
58     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
59     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
60   } else {
61     PetscBool isseq;
62 
63     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
64     if (isseq) {
65       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
66     } else {
67       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
68     }
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "VecView_Plex"
75 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
76 {
77   DM             dm;
78   PetscBool      isvtk;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
83   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
84   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
85   if (isvtk) {
86     Vec         locv;
87     const char *name;
88 
89     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
90     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
91     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
92     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
93     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
94     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
95     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
96   } else {
97     PetscBool isseq;
98 
99     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
100     if (isseq) {
101       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
102     } else {
103       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
104     }
105   }
106   PetscFunctionReturn(0);
107 }
108 
109 #undef __FUNCT__
110 #define __FUNCT__ "DMPlexView_Ascii"
111 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
112 {
113   DM_Plex          *mesh = (DM_Plex*) dm->data;
114   DM                cdm;
115   DMLabel           markers;
116   PetscSection      coordSection;
117   Vec               coordinates;
118   PetscViewerFormat format;
119   PetscErrorCode    ierr;
120 
121   PetscFunctionBegin;
122   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
123   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
124   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
125   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
126   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
127     const char *name;
128     PetscInt    maxConeSize, maxSupportSize;
129     PetscInt    pStart, pEnd, p;
130     PetscMPIInt rank, size;
131 
132     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
133     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
134     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
135     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
136     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
137     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
138     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
142     for (p = pStart; p < pEnd; ++p) {
143       PetscInt dof, off, s;
144 
145       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
146       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
147       for (s = off; s < off+dof; ++s) {
148         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
149       }
150     }
151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
152     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
153     for (p = pStart; p < pEnd; ++p) {
154       PetscInt dof, off, c;
155 
156       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
157       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
158       for (c = off; c < off+dof; ++c) {
159         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
160       }
161     }
162     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
163     ierr = PetscSectionGetChart(coordSection, &pStart, PETSC_NULL);CHKERRQ(ierr);
164     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
165     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
166     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
167     if (size > 1) {
168       PetscSF sf;
169 
170       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
171       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
172     }
173     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
174   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
175     const char  *name;
176     const char  *colors[3] = {"red", "blue", "green"};
177     const int    numColors  = 3;
178     PetscReal    scale      = 2.0;
179     PetscScalar *coords;
180     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
181     PetscMPIInt  rank, size;
182 
183     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
184     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
185     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
186     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
187     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
188     ierr = PetscViewerASCIIPrintf(viewer, "\
189 \\documentclass[crop,multi=false]{standalone}\n\n\
190 \\usepackage{tikz}\n\
191 \\usepackage{pgflibraryshapes}\n\
192 \\usetikzlibrary{backgrounds}\n\
193 \\usetikzlibrary{arrows}\n\
194 \\begin{document}\n\
195 \\section{%s}\n\
196 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
197     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
198     for (p = 0; p < size; ++p) {
199       if (p > 0 && p == size-1) {
200         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
201       } else if (p > 0) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
203       }
204       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
205     }
206     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
207 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
208     /* Plot vertices */
209     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
210     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
211     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
212     for (v = vStart; v < vEnd; ++v) {
213       PetscInt off, dof, d;
214 
215       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
216       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
217       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
218       for (d = 0; d < dof; ++d) {
219         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
220         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
221       }
222       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
223     }
224     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
225     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
226     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
227     /* Plot edges */
228     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
229     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
230     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
231     for (e = eStart; e < eEnd; ++e) {
232       const PetscInt *cone;
233       PetscInt        coneSize, offA, offB, dof, d;
234 
235       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
236       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
237       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
238       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
239       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
240       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
241       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
242       for (d = 0; d < dof; ++d) {
243         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
244         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
245       }
246       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
247     }
248     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
249     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
250     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
251     /* Plot cells */
252     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
253     for (c = cStart; c < cEnd; ++c) {
254       PetscInt *closure = PETSC_NULL;
255       PetscInt  closureSize, firstPoint = -1;
256 
257       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
258       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
259       for (p = 0; p < closureSize*2; p += 2) {
260         const PetscInt point = closure[p];
261 
262         if ((point < vStart) || (point >= vEnd)) continue;
263         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
264         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
265         if (firstPoint < 0) firstPoint = point;
266       }
267       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
268       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
269       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
270     }
271     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
272     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
273     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
274   } else {
275     MPI_Comm    comm = ((PetscObject) dm)->comm;
276     PetscInt   *sizes;
277     PetscInt    locDepth, depth, dim, d;
278     PetscInt    pStart, pEnd, p;
279     PetscMPIInt size;
280 
281     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
282     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
283     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
284     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
285     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
286     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
287     if (depth == 1) {
288       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
289       pEnd = pEnd - pStart;
290       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
291       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
292       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
293       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
294       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
295       pEnd = pEnd - pStart;
296       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
297       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
298       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
299       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
300     } else {
301       for (d = 0; d <= dim; d++) {
302         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
303         pEnd = pEnd - pStart;
304         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
305         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
306         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
307         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
308       }
309     }
310     ierr = PetscFree(sizes);CHKERRQ(ierr);
311   }
312   PetscFunctionReturn(0);
313 }
314 
315 #undef __FUNCT__
316 #define __FUNCT__ "DMView_Plex"
317 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
318 {
319   PetscBool      iascii, isbinary;
320   PetscErrorCode ierr;
321 
322   PetscFunctionBegin;
323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
324   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
325   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
326   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
327   if (iascii) {
328     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
329 #if 0
330   } else if (isbinary) {
331     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
332 #endif
333   }
334   PetscFunctionReturn(0);
335 }
336 
337 #undef __FUNCT__
338 #define __FUNCT__ "DMDestroy_Plex"
339 PetscErrorCode DMDestroy_Plex(DM dm)
340 {
341   DM_Plex       *mesh = (DM_Plex*) dm->data;
342   DMLabel        next  = mesh->labels;
343   PetscErrorCode ierr;
344 
345   PetscFunctionBegin;
346   if (--mesh->refct > 0) PetscFunctionReturn(0);
347   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
348   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
349   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
350   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
353   while (next) {
354     DMLabel tmp = next->next;
355 
356     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
357     next = tmp;
358   }
359   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
360   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
361   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
362   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
363   ierr = PetscFree(mesh);CHKERRQ(ierr);
364   PetscFunctionReturn(0);
365 }
366 
367 #undef __FUNCT__
368 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
369 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
370 {
371   const PetscInt *support = PETSC_NULL;
372   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
373   PetscErrorCode  ierr;
374 
375   PetscFunctionBegin;
376   if (useClosure) {
377     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
378     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
379     for (s = 0; s < supportSize; ++s) {
380       const PetscInt *cone = PETSC_NULL;
381       PetscInt        coneSize, c, q;
382 
383       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
384       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
385       for (c = 0; c < coneSize; ++c) {
386         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
387           if (cone[c] == adj[q]) break;
388         }
389         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
390       }
391     }
392   } else {
393     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
394     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
395     for (s = 0; s < supportSize; ++s) {
396       const PetscInt *cone = PETSC_NULL;
397       PetscInt        coneSize, c, q;
398 
399       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
400       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
401       for (c = 0; c < coneSize; ++c) {
402         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
403           if (cone[c] == adj[q]) break;
404         }
405         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
406       }
407     }
408   }
409   *adjSize = numAdj;
410   PetscFunctionReturn(0);
411 }
412 
413 #undef __FUNCT__
414 #define __FUNCT__ "DMPlexGetAdjacency_Private"
415 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
416 {
417   const PetscInt *star  = tmpClosure;
418   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
419   PetscErrorCode  ierr;
420 
421   PetscFunctionBegin;
422   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
423   for (s = 2; s < starSize*2; s += 2) {
424     const PetscInt *closure = PETSC_NULL;
425     PetscInt        closureSize, c, q;
426 
427     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
428     for (c = 0; c < closureSize*2; c += 2) {
429       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
430         if (closure[c] == adj[q]) break;
431       }
432       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
433     }
434     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
435   }
436   *adjSize = numAdj;
437   PetscFunctionReturn(0);
438 }
439 
440 #undef __FUNCT__
441 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
442 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
443 {
444   DM_Plex *mesh = (DM_Plex*) dm->data;
445 
446   PetscFunctionBegin;
447   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
448   mesh->preallocCenterDim = preallocCenterDim;
449   PetscFunctionReturn(0);
450 }
451 
452 #undef __FUNCT__
453 #define __FUNCT__ "DMPlexPreallocateOperator"
454 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
455 {
456   DM_Plex           *mesh = (DM_Plex*) dm->data;
457   MPI_Comm           comm  = ((PetscObject) dm)->comm;
458   PetscSF            sf, sfDof, sfAdj;
459   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
460   PetscInt           nleaves, l, p;
461   const PetscInt    *leaves;
462   const PetscSFNode *remotes;
463   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
464   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
465   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
466   PetscLayout        rLayout;
467   PetscInt           locRows, rStart, rEnd, r;
468   PetscMPIInt        size;
469   PetscBool          useClosure, debug = PETSC_FALSE;
470   PetscErrorCode     ierr;
471 
472   PetscFunctionBegin;
473   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
474   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
475   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
476   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
477   /* Create dof SF based on point SF */
478   if (debug) {
479     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
480     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
481     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
485   }
486   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
487   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
488   if (debug) {
489     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
490     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
491   }
492   /* Create section for dof adjacency (dof ==> # adj dof) */
493   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
494   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
495   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
496   if (mesh->preallocCenterDim == dim) {
497     useClosure = PETSC_FALSE;
498   } else if (mesh->preallocCenterDim == 0) {
499     useClosure = PETSC_TRUE;
500   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
501 
502   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
503   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
504   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
505   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
508   /*   Fill in the ghost dofs on the interface */
509   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
510   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
511   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
512 
513   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
514   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
515 
516   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
517 
518   /*
519    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
520     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
521        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
522     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
523        Create sfAdj connecting rootSectionAdj and leafSectionAdj
524     3. Visit unowned points on interface, write adjacencies to adj
525        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
526     4. Visit owned points on interface, write adjacencies to rootAdj
527        Remove redundancy in rootAdj
528    ** The last two traversals use transitive closure
529     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
530        Allocate memory addressed by sectionAdj (cols)
531     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
532    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
533   */
534 
535   for (l = 0; l < nleaves; ++l) {
536     PetscInt dof, off, d, q;
537     PetscInt p = leaves[l], numAdj = maxAdjSize;
538 
539     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
540     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
541     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
542     for (q = 0; q < numAdj; ++q) {
543       PetscInt ndof, ncdof;
544 
545       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
546       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
547       for (d = off; d < off+dof; ++d) {
548         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
549       }
550     }
551   }
552   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
553   if (debug) {
554     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
555     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
556   }
557   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
558   if (size > 1) {
559     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
560     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
561   }
562   if (debug) {
563     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
564     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
565   }
566   /* Add in local adjacency sizes for owned dofs on interface (roots) */
567   for (p = pStart; p < pEnd; ++p) {
568     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
569 
570     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
571     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
572     if (!dof) continue;
573     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
574     if (adof <= 0) continue;
575     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
576     for (q = 0; q < numAdj; ++q) {
577       PetscInt ndof, ncdof;
578 
579       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
580       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
581       for (d = off; d < off+dof; ++d) {
582         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
583       }
584     }
585   }
586   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
587   if (debug) {
588     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
589     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
590   }
591   /* Create adj SF based on dof SF */
592   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
593   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
596     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
597   }
598   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
599   /* Create leaf adjacency */
600   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
601   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
602   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
603   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
604   for (l = 0; l < nleaves; ++l) {
605     PetscInt dof, off, d, q;
606     PetscInt p = leaves[l], numAdj = maxAdjSize;
607 
608     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
609     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
610     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
611     for (d = off; d < off+dof; ++d) {
612       PetscInt aoff, i = 0;
613 
614       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
615       for (q = 0; q < numAdj; ++q) {
616         PetscInt ndof, ncdof, ngoff, nd;
617 
618         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
619         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
620         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
621         for (nd = 0; nd < ndof-ncdof; ++nd) {
622           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
623           ++i;
624         }
625       }
626     }
627   }
628   /* Debugging */
629   if (debug) {
630     IS tmp;
631     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
632     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
633     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
634   }
635   /* Gather adjacenct indices to root */
636   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
637   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
638   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
639   if (size > 1) {
640     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
641     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
642   }
643   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
644   ierr = PetscFree(adj);CHKERRQ(ierr);
645   /* Debugging */
646   if (debug) {
647     IS tmp;
648     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
649     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
650     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
651   }
652   /* Add in local adjacency indices for owned dofs on interface (roots) */
653   for (p = pStart; p < pEnd; ++p) {
654     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
655 
656     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
657     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
658     if (!dof) continue;
659     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
660     if (adof <= 0) continue;
661     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
662     for (d = off; d < off+dof; ++d) {
663       PetscInt adof, aoff, i;
664 
665       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
666       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
667       i    = adof-1;
668       for (q = 0; q < numAdj; ++q) {
669         PetscInt ndof, ncdof, ngoff, nd;
670 
671         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
672         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
673         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
674         for (nd = 0; nd < ndof-ncdof; ++nd) {
675           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
676           --i;
677         }
678       }
679     }
680   }
681   /* Debugging */
682   if (debug) {
683     IS tmp;
684     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
685     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
686     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
687   }
688   /* Compress indices */
689   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
690   for (p = pStart; p < pEnd; ++p) {
691     PetscInt dof, cdof, off, d;
692     PetscInt adof, aoff;
693 
694     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
695     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
696     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
697     if (!dof) continue;
698     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
699     if (adof <= 0) continue;
700     for (d = off; d < off+dof-cdof; ++d) {
701       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
702       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
703       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
704       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
705     }
706   }
707   /* Debugging */
708   if (debug) {
709     IS tmp;
710     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
711     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
712     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
713     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
714     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
715   }
716   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
717   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
718   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
719   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
720   for (p = pStart; p < pEnd; ++p) {
721     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
722     PetscBool found  = PETSC_TRUE;
723 
724     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
725     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
726     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
727     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
728     for (d = 0; d < dof-cdof; ++d) {
729       PetscInt ldof, rdof;
730 
731       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
732       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
733       if (ldof > 0) {
734         /* We do not own this point */
735       } else if (rdof > 0) {
736         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
737       } else {
738         found = PETSC_FALSE;
739       }
740     }
741     if (found) continue;
742     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
743     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
744     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
745     for (q = 0; q < numAdj; ++q) {
746       PetscInt ndof, ncdof, noff;
747 
748       /* Adjacent points may not be in the section chart */
749       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
750       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
751       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
752       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
753       for (d = goff; d < goff+dof-cdof; ++d) {
754         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
755       }
756     }
757   }
758   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
759   if (debug) {
760     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
761     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
762   }
763   /* Get adjacent indices */
764   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
765   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
766   for (p = pStart; p < pEnd; ++p) {
767     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
768     PetscBool found  = PETSC_TRUE;
769 
770     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
771     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
772     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
773     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
774     for (d = 0; d < dof-cdof; ++d) {
775       PetscInt ldof, rdof;
776 
777       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
778       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
779       if (ldof > 0) {
780         /* We do not own this point */
781       } else if (rdof > 0) {
782         PetscInt aoff, roff;
783 
784         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
785         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
786         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
787       } else {
788         found = PETSC_FALSE;
789       }
790     }
791     if (found) continue;
792     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
793     for (d = goff; d < goff+dof-cdof; ++d) {
794       PetscInt adof, aoff, i = 0;
795 
796       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
797       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
798       for (q = 0; q < numAdj; ++q) {
799         PetscInt        ndof, ncdof, ngoff, nd;
800         const PetscInt *ncind;
801 
802         /* Adjacent points may not be in the section chart */
803         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
804         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
805         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
806         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
807         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
808         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
809           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
810         }
811       }
812       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);
813     }
814   }
815   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
816   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
817   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
818   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
819   /* Debugging */
820   if (debug) {
821     IS tmp;
822     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
823     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
824     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
825   }
826   /* Create allocation vectors from adjacency graph */
827   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
828   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
829   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
830   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
831   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
832   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
833   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
834   /* Only loop over blocks of rows */
835   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
836   for (r = rStart/bs; r < rEnd/bs; ++r) {
837     const PetscInt row = r*bs;
838     PetscInt       numCols, cStart, c;
839 
840     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
841     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
842     for (c = cStart; c < cStart+numCols; ++c) {
843       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
844         ++dnz[r-rStart];
845         if (cols[c] >= row) ++dnzu[r-rStart];
846       } else {
847         ++onz[r-rStart];
848         if (cols[c] >= row) ++onzu[r-rStart];
849       }
850     }
851   }
852   if (bs > 1) {
853     for (r = 0; r < locRows/bs; ++r) {
854       dnz[r]  /= bs;
855       onz[r]  /= bs;
856       dnzu[r] /= bs;
857       onzu[r] /= bs;
858     }
859   }
860   /* Set matrix pattern */
861   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
862   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
863   /* Fill matrix with zeros */
864   if (fillMatrix) {
865     PetscScalar *values;
866     PetscInt     maxRowLen = 0;
867 
868     for (r = rStart; r < rEnd; ++r) {
869       PetscInt len;
870 
871       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
872       maxRowLen = PetscMax(maxRowLen, len);
873     }
874     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
875     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
876     for (r = rStart; r < rEnd; ++r) {
877       PetscInt numCols, cStart;
878 
879       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
880       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
881       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
882     }
883     ierr = PetscFree(values);CHKERRQ(ierr);
884     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
885     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
886   }
887   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
888   ierr = PetscFree(cols);CHKERRQ(ierr);
889   PetscFunctionReturn(0);
890 }
891 
892 #if 0
893 #undef __FUNCT__
894 #define __FUNCT__ "DMPlexPreallocateOperator_2"
895 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
896 {
897   PetscInt       *tmpClosure,*tmpAdj,*visits;
898   PetscInt        c,cStart,cEnd,pStart,pEnd;
899   PetscErrorCode  ierr;
900 
901   PetscFunctionBegin;
902   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
903   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
904   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
905 
906   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
907 
908   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910 
911   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
912   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
914   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
915   for (c=cStart; c<cEnd; c++) {
916     PetscInt *support = tmpClosure;
917     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
918     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
919   }
920   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
921   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
923   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924 
925   ierr = PetscSFGetRanks();CHKERRQ(ierr);
926 
927 
928   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
929   for (c=cStart; c<cEnd; c++) {
930     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
931     /*
932      Depth-first walk of transitive closure.
933      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.
934      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
935      */
936   }
937 
938   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
939   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
940   PetscFunctionReturn(0);
941 }
942 #endif
943 
944 #undef __FUNCT__
945 #define __FUNCT__ "DMCreateMatrix_Plex"
946 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
947 {
948   PetscSection   section, sectionGlobal;
949   PetscInt       bs = -1;
950   PetscInt       localSize;
951   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
952   PetscErrorCode ierr;
953 
954   PetscFunctionBegin;
955 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
956   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
957 #endif
958   if (!mtype) mtype = MATAIJ;
959   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
960   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
961   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
962   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
963   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
964   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
965   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
966   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
967   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
974   /* Check for symmetric storage */
975   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
976   if (isSymmetric) {
977     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
978   }
979   if (!isShell) {
980     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
981     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
982 
983     if (bs < 0) {
984       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
985         PetscInt pStart, pEnd, p, dof;
986 
987         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
988         for (p = pStart; p < pEnd; ++p) {
989           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
990           if (dof) {
991             if (bs < 0) {
992               bs = dof;
993             } else if (bs != dof) {
994               /* Layout does not admit a pointwise block size */
995               bs = 1;
996               break;
997             }
998           }
999         }
1000         /* Must have same blocksize on all procs (some might have no points) */
1001         bsLocal = bs;
1002         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1003         bsLocal = bs < 0 ? bsMax : bs;
1004         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1005         if (bsMin != bsMax) {
1006           bs = 1;
1007         } else {
1008           bs = bsMax;
1009         }
1010       } else {
1011         bs = 1;
1012       }
1013     }
1014     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1015     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1016     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1017     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1018     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1019     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1020     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1021   }
1022   PetscFunctionReturn(0);
1023 }
1024 
1025 #undef __FUNCT__
1026 #define __FUNCT__ "DMPlexGetDimension"
1027 /*@
1028   DMPlexGetDimension - Return the topological mesh dimension
1029 
1030   Not collective
1031 
1032   Input Parameter:
1033 . mesh - The DMPlex
1034 
1035   Output Parameter:
1036 . dim - The topological mesh dimension
1037 
1038   Level: beginner
1039 
1040 .seealso: DMPlexCreate()
1041 @*/
1042 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1043 {
1044   DM_Plex *mesh = (DM_Plex*) dm->data;
1045 
1046   PetscFunctionBegin;
1047   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1048   PetscValidPointer(dim, 2);
1049   *dim = mesh->dim;
1050   PetscFunctionReturn(0);
1051 }
1052 
1053 #undef __FUNCT__
1054 #define __FUNCT__ "DMPlexSetDimension"
1055 /*@
1056   DMPlexSetDimension - Set the topological mesh dimension
1057 
1058   Collective on mesh
1059 
1060   Input Parameters:
1061 + mesh - The DMPlex
1062 - dim - The topological mesh dimension
1063 
1064   Level: beginner
1065 
1066 .seealso: DMPlexCreate()
1067 @*/
1068 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1069 {
1070   DM_Plex *mesh = (DM_Plex*) dm->data;
1071 
1072   PetscFunctionBegin;
1073   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1074   PetscValidLogicalCollectiveInt(dm, dim, 2);
1075   mesh->dim               = dim;
1076   mesh->preallocCenterDim = dim;
1077   PetscFunctionReturn(0);
1078 }
1079 
1080 #undef __FUNCT__
1081 #define __FUNCT__ "DMPlexGetChart"
1082 /*@
1083   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1084 
1085   Not collective
1086 
1087   Input Parameter:
1088 . mesh - The DMPlex
1089 
1090   Output Parameters:
1091 + pStart - The first mesh point
1092 - pEnd   - The upper bound for mesh points
1093 
1094   Level: beginner
1095 
1096 .seealso: DMPlexCreate(), DMPlexSetChart()
1097 @*/
1098 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1099 {
1100   DM_Plex       *mesh = (DM_Plex*) dm->data;
1101   PetscErrorCode ierr;
1102 
1103   PetscFunctionBegin;
1104   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1105   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1106   PetscFunctionReturn(0);
1107 }
1108 
1109 #undef __FUNCT__
1110 #define __FUNCT__ "DMPlexSetChart"
1111 /*@
1112   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1113 
1114   Not collective
1115 
1116   Input Parameters:
1117 + mesh - The DMPlex
1118 . pStart - The first mesh point
1119 - pEnd   - The upper bound for mesh points
1120 
1121   Output Parameters:
1122 
1123   Level: beginner
1124 
1125 .seealso: DMPlexCreate(), DMPlexGetChart()
1126 @*/
1127 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1128 {
1129   DM_Plex       *mesh = (DM_Plex*) dm->data;
1130   PetscErrorCode ierr;
1131 
1132   PetscFunctionBegin;
1133   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1134   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1135   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1136   PetscFunctionReturn(0);
1137 }
1138 
1139 #undef __FUNCT__
1140 #define __FUNCT__ "DMPlexGetConeSize"
1141 /*@
1142   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1143 
1144   Not collective
1145 
1146   Input Parameters:
1147 + mesh - The DMPlex
1148 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1149 
1150   Output Parameter:
1151 . size - The cone size for point p
1152 
1153   Level: beginner
1154 
1155 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1156 @*/
1157 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1158 {
1159   DM_Plex       *mesh = (DM_Plex*) dm->data;
1160   PetscErrorCode ierr;
1161 
1162   PetscFunctionBegin;
1163   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1164   PetscValidPointer(size, 3);
1165   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1166   PetscFunctionReturn(0);
1167 }
1168 
1169 #undef __FUNCT__
1170 #define __FUNCT__ "DMPlexSetConeSize"
1171 /*@
1172   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1173 
1174   Not collective
1175 
1176   Input Parameters:
1177 + mesh - The DMPlex
1178 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1179 - size - The cone size for point p
1180 
1181   Output Parameter:
1182 
1183   Note:
1184   This should be called after DMPlexSetChart().
1185 
1186   Level: beginner
1187 
1188 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1189 @*/
1190 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1191 {
1192   DM_Plex       *mesh = (DM_Plex*) dm->data;
1193   PetscErrorCode ierr;
1194 
1195   PetscFunctionBegin;
1196   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1197   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1198 
1199   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1200   PetscFunctionReturn(0);
1201 }
1202 
1203 #undef __FUNCT__
1204 #define __FUNCT__ "DMPlexGetCone"
1205 /*@C
1206   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1207 
1208   Not collective
1209 
1210   Input Parameters:
1211 + mesh - The DMPlex
1212 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1213 
1214   Output Parameter:
1215 . cone - An array of points which are on the in-edges for point p
1216 
1217   Level: beginner
1218 
1219   Note:
1220   This routine is not available in Fortran.
1221 
1222 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1223 @*/
1224 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1225 {
1226   DM_Plex       *mesh = (DM_Plex*) dm->data;
1227   PetscInt       off;
1228   PetscErrorCode ierr;
1229 
1230   PetscFunctionBegin;
1231   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1232   PetscValidPointer(cone, 3);
1233   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1234   *cone = &mesh->cones[off];
1235   PetscFunctionReturn(0);
1236 }
1237 
1238 #undef __FUNCT__
1239 #define __FUNCT__ "DMPlexSetCone"
1240 /*@
1241   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1242 
1243   Not collective
1244 
1245   Input Parameters:
1246 + mesh - The DMPlex
1247 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1248 - cone - An array of points which are on the in-edges for point p
1249 
1250   Output Parameter:
1251 
1252   Note:
1253   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1254 
1255   Level: beginner
1256 
1257 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1258 @*/
1259 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1260 {
1261   DM_Plex       *mesh = (DM_Plex*) dm->data;
1262   PetscInt       pStart, pEnd;
1263   PetscInt       dof, off, c;
1264   PetscErrorCode ierr;
1265 
1266   PetscFunctionBegin;
1267   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1268   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1269   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1270   if (dof) PetscValidPointer(cone, 3);
1271   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1272   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1273   for (c = 0; c < dof; ++c) {
1274     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1275     mesh->cones[off+c] = cone[c];
1276   }
1277   PetscFunctionReturn(0);
1278 }
1279 
1280 #undef __FUNCT__
1281 #define __FUNCT__ "DMPlexGetConeOrientation"
1282 /*@C
1283   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1284 
1285   Not collective
1286 
1287   Input Parameters:
1288 + mesh - The DMPlex
1289 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1290 
1291   Output Parameter:
1292 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1293                     integer giving the prescription for cone traversal. If it is negative, the cone is
1294                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1295                     the index of the cone point on which to start.
1296 
1297   Level: beginner
1298 
1299   Note:
1300   This routine is not available in Fortran.
1301 
1302 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1303 @*/
1304 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1305 {
1306   DM_Plex       *mesh = (DM_Plex*) dm->data;
1307   PetscInt       off;
1308   PetscErrorCode ierr;
1309 
1310   PetscFunctionBegin;
1311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1312 #if defined(PETSC_USE_DEBUG)
1313   {
1314     PetscInt dof;
1315     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1316     if (dof) PetscValidPointer(coneOrientation, 3);
1317   }
1318 #endif
1319   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1320 
1321   *coneOrientation = &mesh->coneOrientations[off];
1322   PetscFunctionReturn(0);
1323 }
1324 
1325 #undef __FUNCT__
1326 #define __FUNCT__ "DMPlexSetConeOrientation"
1327 /*@
1328   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1329 
1330   Not collective
1331 
1332   Input Parameters:
1333 + mesh - The DMPlex
1334 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1335 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1336                     integer giving the prescription for cone traversal. If it is negative, the cone is
1337                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1338                     the index of the cone point on which to start.
1339 
1340   Output Parameter:
1341 
1342   Note:
1343   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1344 
1345   Level: beginner
1346 
1347 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1348 @*/
1349 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1350 {
1351   DM_Plex       *mesh = (DM_Plex*) dm->data;
1352   PetscInt       pStart, pEnd;
1353   PetscInt       dof, off, c;
1354   PetscErrorCode ierr;
1355 
1356   PetscFunctionBegin;
1357   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1358   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1359   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1360   if (dof) PetscValidPointer(coneOrientation, 3);
1361   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1362   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1363   for (c = 0; c < dof; ++c) {
1364     PetscInt cdof, o = coneOrientation[c];
1365 
1366     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1367     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1368     mesh->coneOrientations[off+c] = o;
1369   }
1370   PetscFunctionReturn(0);
1371 }
1372 
1373 #undef __FUNCT__
1374 #define __FUNCT__ "DMPlexInsertCone"
1375 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1376 {
1377   DM_Plex       *mesh = (DM_Plex*) dm->data;
1378   PetscInt       pStart, pEnd;
1379   PetscInt       dof, off;
1380   PetscErrorCode ierr;
1381 
1382   PetscFunctionBegin;
1383   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1384   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1385   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1386   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1387   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1388   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1389   if (conePos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1390   mesh->cones[off+conePos] = conePoint;
1391   PetscFunctionReturn(0);
1392 }
1393 
1394 #undef __FUNCT__
1395 #define __FUNCT__ "DMPlexGetSupportSize"
1396 /*@
1397   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1398 
1399   Not collective
1400 
1401   Input Parameters:
1402 + mesh - The DMPlex
1403 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1404 
1405   Output Parameter:
1406 . size - The support size for point p
1407 
1408   Level: beginner
1409 
1410 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1411 @*/
1412 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1413 {
1414   DM_Plex       *mesh = (DM_Plex*) dm->data;
1415   PetscErrorCode ierr;
1416 
1417   PetscFunctionBegin;
1418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1419   PetscValidPointer(size, 3);
1420   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1421   PetscFunctionReturn(0);
1422 }
1423 
1424 #undef __FUNCT__
1425 #define __FUNCT__ "DMPlexSetSupportSize"
1426 /*@
1427   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1428 
1429   Not collective
1430 
1431   Input Parameters:
1432 + mesh - The DMPlex
1433 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1434 - size - The support size for point p
1435 
1436   Output Parameter:
1437 
1438   Note:
1439   This should be called after DMPlexSetChart().
1440 
1441   Level: beginner
1442 
1443 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1444 @*/
1445 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1446 {
1447   DM_Plex       *mesh = (DM_Plex*) dm->data;
1448   PetscErrorCode ierr;
1449 
1450   PetscFunctionBegin;
1451   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1452   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1453 
1454   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1455   PetscFunctionReturn(0);
1456 }
1457 
1458 #undef __FUNCT__
1459 #define __FUNCT__ "DMPlexGetSupport"
1460 /*@C
1461   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1462 
1463   Not collective
1464 
1465   Input Parameters:
1466 + mesh - The DMPlex
1467 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1468 
1469   Output Parameter:
1470 . support - An array of points which are on the out-edges for point p
1471 
1472   Level: beginner
1473 
1474 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1475 @*/
1476 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1477 {
1478   DM_Plex       *mesh = (DM_Plex*) dm->data;
1479   PetscInt       off;
1480   PetscErrorCode ierr;
1481 
1482   PetscFunctionBegin;
1483   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1484   PetscValidPointer(support, 3);
1485   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1486   *support = &mesh->supports[off];
1487   PetscFunctionReturn(0);
1488 }
1489 
1490 #undef __FUNCT__
1491 #define __FUNCT__ "DMPlexSetSupport"
1492 /*@
1493   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1494 
1495   Not collective
1496 
1497   Input Parameters:
1498 + mesh - The DMPlex
1499 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1500 - support - An array of points which are on the in-edges for point p
1501 
1502   Output Parameter:
1503 
1504   Note:
1505   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1506 
1507   Level: beginner
1508 
1509 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1510 @*/
1511 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1512 {
1513   DM_Plex       *mesh = (DM_Plex*) dm->data;
1514   PetscInt       pStart, pEnd;
1515   PetscInt       dof, off, c;
1516   PetscErrorCode ierr;
1517 
1518   PetscFunctionBegin;
1519   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1520   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1521   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1522   if (dof) PetscValidPointer(support, 3);
1523   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1524   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1525   for (c = 0; c < dof; ++c) {
1526     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1527     mesh->supports[off+c] = support[c];
1528   }
1529   PetscFunctionReturn(0);
1530 }
1531 
1532 #undef __FUNCT__
1533 #define __FUNCT__ "DMPlexInsertSupport"
1534 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1535 {
1536   DM_Plex       *mesh = (DM_Plex*) dm->data;
1537   PetscInt       pStart, pEnd;
1538   PetscInt       dof, off;
1539   PetscErrorCode ierr;
1540 
1541   PetscFunctionBegin;
1542   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1543   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1544   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1545   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1546   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1547   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1548   if (supportPos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1549   mesh->supports[off+supportPos] = supportPoint;
1550   PetscFunctionReturn(0);
1551 }
1552 
1553 #undef __FUNCT__
1554 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1555 /*@C
1556   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1557 
1558   Not collective
1559 
1560   Input Parameters:
1561 + mesh - The DMPlex
1562 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1563 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1564 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1565 
1566   Output Parameters:
1567 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1568 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1569 
1570   Note:
1571   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1572 
1573   Level: beginner
1574 
1575 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1576 @*/
1577 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1578 {
1579   DM_Plex        *mesh = (DM_Plex*) dm->data;
1580   PetscInt       *closure, *fifo;
1581   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1582   PetscInt        tmpSize, t;
1583   PetscInt        depth       = 0, maxSize;
1584   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1585   PetscErrorCode  ierr;
1586 
1587   PetscFunctionBegin;
1588   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1589   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1590   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1591   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1592   if (*points) {
1593     closure = *points;
1594   } else {
1595     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1596   }
1597   closure[0] = p; closure[1] = 0;
1598   /* This is only 1-level */
1599   if (useCone) {
1600     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1601     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1602     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1603   } else {
1604     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1605     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1606   }
1607   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1608     const PetscInt cp = tmp[t];
1609     const PetscInt co = tmpO ? tmpO[t] : 0;
1610 
1611     closure[closureSize]   = cp;
1612     closure[closureSize+1] = co;
1613     fifo[fifoSize]         = cp;
1614     fifo[fifoSize+1]       = co;
1615   }
1616   while (fifoSize - fifoStart) {
1617     const PetscInt q   = fifo[fifoStart];
1618     const PetscInt o   = fifo[fifoStart+1];
1619     const PetscInt rev = o >= 0 ? 0 : 1;
1620     const PetscInt off = rev ? -(o+1) : o;
1621 
1622     if (useCone) {
1623       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1624       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1625       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1626     } else {
1627       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1628       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1629       tmpO = PETSC_NULL;
1630     }
1631     for (t = 0; t < tmpSize; ++t) {
1632       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1633       const PetscInt cp = tmp[i];
1634       /* Must propogate orientation */
1635       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1636       PetscInt       c;
1637 
1638       /* Check for duplicate */
1639       for (c = 0; c < closureSize; c += 2) {
1640         if (closure[c] == cp) break;
1641       }
1642       if (c == closureSize) {
1643         closure[closureSize]   = cp;
1644         closure[closureSize+1] = co;
1645         fifo[fifoSize]         = cp;
1646         fifo[fifoSize+1]       = co;
1647         closureSize           += 2;
1648         fifoSize              += 2;
1649       }
1650     }
1651     fifoStart += 2;
1652   }
1653   if (numPoints) *numPoints = closureSize/2;
1654   if (points)    *points    = closure;
1655   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1656   PetscFunctionReturn(0);
1657 }
1658 
1659 #undef __FUNCT__
1660 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1661 /*@C
1662   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1663 
1664   Not collective
1665 
1666   Input Parameters:
1667 + mesh - The DMPlex
1668 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1669 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1670 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1671 
1672   Output Parameters:
1673 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1674 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1675 
1676   Note:
1677   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1678 
1679   Level: beginner
1680 
1681 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1682 @*/
1683 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1684 {
1685   PetscErrorCode ierr;
1686 
1687   PetscFunctionBegin;
1688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1689   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1690   PetscFunctionReturn(0);
1691 }
1692 
1693 #undef __FUNCT__
1694 #define __FUNCT__ "DMPlexGetFaces"
1695 /*
1696   DMPlexGetFaces -
1697 
1698   Note: This will only work for cell-vertex meshes.
1699 */
1700 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1701 {
1702   DM_Plex        *mesh = (DM_Plex*) dm->data;
1703   const PetscInt *cone = PETSC_NULL;
1704   PetscInt        depth = 0, dim, coneSize;
1705   PetscErrorCode  ierr;
1706 
1707   PetscFunctionBegin;
1708   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1709   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1710   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1711   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1712   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1713   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1714   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1715   switch (dim) {
1716   case 2:
1717     switch (coneSize) {
1718     case 3:
1719       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1720       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1721       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1722       *numFaces         = 3;
1723       *faceSize         = 2;
1724       *faces            = mesh->facesTmp;
1725       break;
1726     case 4:
1727       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1728       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1729       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1730       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1731       *numFaces         = 4;
1732       *faceSize         = 2;
1733       *faces            = mesh->facesTmp;
1734       break;
1735     default:
1736       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1737     }
1738     break;
1739   case 3:
1740     switch (coneSize) {
1741     case 3:
1742       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1743       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1744       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1745       *numFaces         = 3;
1746       *faceSize         = 2;
1747       *faces            = mesh->facesTmp;
1748       break;
1749     case 4:
1750       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1751       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1752       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1753       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1754       *numFaces         = 4;
1755       *faceSize         = 3;
1756       *faces            = mesh->facesTmp;
1757       break;
1758     default:
1759       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1760     }
1761     break;
1762   default:
1763     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1764   }
1765   PetscFunctionReturn(0);
1766 }
1767 
1768 #undef __FUNCT__
1769 #define __FUNCT__ "DMPlexGetMaxSizes"
1770 /*@
1771   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1772 
1773   Not collective
1774 
1775   Input Parameter:
1776 . mesh - The DMPlex
1777 
1778   Output Parameters:
1779 + maxConeSize - The maximum number of in-edges
1780 - maxSupportSize - The maximum number of out-edges
1781 
1782   Level: beginner
1783 
1784 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1785 @*/
1786 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1787 {
1788   DM_Plex *mesh = (DM_Plex*) dm->data;
1789 
1790   PetscFunctionBegin;
1791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1792   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1793   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1794   PetscFunctionReturn(0);
1795 }
1796 
1797 #undef __FUNCT__
1798 #define __FUNCT__ "DMSetUp_Plex"
1799 PetscErrorCode DMSetUp_Plex(DM dm)
1800 {
1801   DM_Plex       *mesh = (DM_Plex*) dm->data;
1802   PetscInt       size;
1803   PetscErrorCode ierr;
1804 
1805   PetscFunctionBegin;
1806   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1807   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1808   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1809   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1810   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1811   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1812   if (mesh->maxSupportSize) {
1813     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1814     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1815     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1816   }
1817   PetscFunctionReturn(0);
1818 }
1819 
1820 #undef __FUNCT__
1821 #define __FUNCT__ "DMCreateSubDM_Plex"
1822 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1823 {
1824   PetscSection   section, sectionGlobal;
1825   PetscInt      *subIndices;
1826   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1827   PetscErrorCode ierr;
1828 
1829   PetscFunctionBegin;
1830   if (!numFields) PetscFunctionReturn(0);
1831   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1832   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1833   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1834   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1835   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1836   if (numFields > nF) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1837   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1838   for (p = pStart; p < pEnd; ++p) {
1839     PetscInt gdof;
1840 
1841     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1842     if (gdof > 0) {
1843       for (f = 0; f < numFields; ++f) {
1844         PetscInt fdof, fcdof;
1845 
1846         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1847         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1848         subSize += fdof-fcdof;
1849       }
1850     }
1851   }
1852   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1853   for (p = pStart; p < pEnd; ++p) {
1854     PetscInt gdof, goff;
1855 
1856     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1857     if (gdof > 0) {
1858       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1859       for (f = 0; f < numFields; ++f) {
1860         PetscInt fdof, fcdof, fc, f2, poff = 0;
1861 
1862         /* Can get rid of this loop by storing field information in the global section */
1863         for (f2 = 0; f2 < fields[f]; ++f2) {
1864           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1865           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1866           poff += fdof-fcdof;
1867         }
1868         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1869         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1870         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1871           subIndices[subOff] = goff+poff+fc;
1872         }
1873       }
1874     }
1875   }
1876   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1877   if (subdm) {
1878     PetscSection subsection;
1879     PetscBool    haveNull = PETSC_FALSE;
1880     PetscInt     f, nf = 0;
1881 
1882     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1883     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1884     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1885     for (f = 0; f < numFields; ++f) {
1886       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1887       if ((*subdm)->nullspaceConstructors[f]) {
1888         haveNull = PETSC_TRUE;
1889         nf       = f;
1890       }
1891     }
1892     if (haveNull) {
1893       MatNullSpace nullSpace;
1894 
1895       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1896       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1897       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1898     }
1899     if (dm->fields) {
1900       if (nF != dm->numFields) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1901       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1902       for (f = 0; f < numFields; ++f) {
1903         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1904       }
1905       if (numFields == 1) {
1906         MatNullSpace space;
1907         Mat          pmat;
1908 
1909         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1910         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1911         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1912         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1913         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1914         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1915       }
1916     }
1917   }
1918   PetscFunctionReturn(0);
1919 }
1920 
1921 #undef __FUNCT__
1922 #define __FUNCT__ "DMPlexSymmetrize"
1923 /*@
1924   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1925 
1926   Not collective
1927 
1928   Input Parameter:
1929 . mesh - The DMPlex
1930 
1931   Output Parameter:
1932 
1933   Note:
1934   This should be called after all calls to DMPlexSetCone()
1935 
1936   Level: beginner
1937 
1938 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1939 @*/
1940 PetscErrorCode DMPlexSymmetrize(DM dm)
1941 {
1942   DM_Plex       *mesh = (DM_Plex*) dm->data;
1943   PetscInt      *offsets;
1944   PetscInt       supportSize;
1945   PetscInt       pStart, pEnd, p;
1946   PetscErrorCode ierr;
1947 
1948   PetscFunctionBegin;
1949   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1950   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1951   /* Calculate support sizes */
1952   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1953   for (p = pStart; p < pEnd; ++p) {
1954     PetscInt dof, off, c;
1955 
1956     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1957     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1958     for (c = off; c < off+dof; ++c) {
1959       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1960     }
1961   }
1962   for (p = pStart; p < pEnd; ++p) {
1963     PetscInt dof;
1964 
1965     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1966 
1967     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1968   }
1969   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1970   /* Calculate supports */
1971   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1972   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1973   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1974   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1975   for (p = pStart; p < pEnd; ++p) {
1976     PetscInt dof, off, c;
1977 
1978     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1979     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1980     for (c = off; c < off+dof; ++c) {
1981       const PetscInt q = mesh->cones[c];
1982       PetscInt       offS;
1983 
1984       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1985 
1986       mesh->supports[offS+offsets[q]] = p;
1987       ++offsets[q];
1988     }
1989   }
1990   ierr = PetscFree(offsets);CHKERRQ(ierr);
1991   PetscFunctionReturn(0);
1992 }
1993 
1994 #undef __FUNCT__
1995 #define __FUNCT__ "DMPlexSetDepth_Private"
1996 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1997 {
1998   PetscInt       d;
1999   PetscErrorCode ierr;
2000 
2001   PetscFunctionBegin;
2002   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
2003   if (d < 0) {
2004     /* We are guaranteed that the point has a cone since the depth was not yet set */
2005     const PetscInt *cone = PETSC_NULL;
2006     PetscInt        dCone;
2007 
2008     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2009     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2010     d    = dCone+1;
2011     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2012   }
2013   *depth = d;
2014   PetscFunctionReturn(0);
2015 }
2016 
2017 #undef __FUNCT__
2018 #define __FUNCT__ "DMPlexStratify"
2019 /*@
2020   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2021   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2022   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2023   the DAG.
2024 
2025   Not collective
2026 
2027   Input Parameter:
2028 . mesh - The DMPlex
2029 
2030   Output Parameter:
2031 
2032   Notes:
2033   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2034   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2035 
2036   This should be called after all calls to DMPlexSymmetrize()
2037 
2038   Level: beginner
2039 
2040 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2041 @*/
2042 PetscErrorCode DMPlexStratify(DM dm)
2043 {
2044   DM_Plex       *mesh = (DM_Plex*) dm->data;
2045   PetscInt       pStart, pEnd, p;
2046   PetscInt       numRoots = 0, numLeaves = 0;
2047   PetscErrorCode ierr;
2048 
2049   PetscFunctionBegin;
2050   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2051   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2052   /* Calculate depth */
2053   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2054   /* Initialize roots and count leaves */
2055   for (p = pStart; p < pEnd; ++p) {
2056     PetscInt coneSize, supportSize;
2057 
2058     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2059     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2060     if (!coneSize && supportSize) {
2061       ++numRoots;
2062       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2063     } else if (!supportSize && coneSize) {
2064       ++numLeaves;
2065     } else if (!supportSize && !coneSize) {
2066       /* Isolated points */
2067       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2068     }
2069   }
2070   if (numRoots + numLeaves == (pEnd - pStart)) {
2071     for (p = pStart; p < pEnd; ++p) {
2072       PetscInt coneSize, supportSize;
2073 
2074       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2075       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2076       if (!supportSize && coneSize) {
2077         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2078       }
2079     }
2080   } else {
2081     /* This might be slow since lookup is not fast */
2082     for (p = pStart; p < pEnd; ++p) {
2083       PetscInt depth;
2084 
2085       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2086     }
2087   }
2088   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2089   PetscFunctionReturn(0);
2090 }
2091 
2092 #undef __FUNCT__
2093 #define __FUNCT__ "DMPlexGetJoin"
2094 /*@C
2095   DMPlexGetJoin - Get an array for the join of the set of points
2096 
2097   Not Collective
2098 
2099   Input Parameters:
2100 + dm - The DMPlex object
2101 . numPoints - The number of input points for the join
2102 - points - The input points
2103 
2104   Output Parameters:
2105 + numCoveredPoints - The number of points in the join
2106 - coveredPoints - The points in the join
2107 
2108   Level: intermediate
2109 
2110   Note: Currently, this is restricted to a single level join
2111 
2112 .keywords: mesh
2113 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2114 @*/
2115 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2116 {
2117   DM_Plex       *mesh = (DM_Plex*) dm->data;
2118   PetscInt      *join[2];
2119   PetscInt       joinSize, i = 0;
2120   PetscInt       dof, off, p, c, m;
2121   PetscErrorCode ierr;
2122 
2123   PetscFunctionBegin;
2124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2125   PetscValidPointer(points, 2);
2126   PetscValidPointer(numCoveredPoints, 3);
2127   PetscValidPointer(coveredPoints, 4);
2128   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2129   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2130   /* Copy in support of first point */
2131   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2132   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2133   for (joinSize = 0; joinSize < dof; ++joinSize) {
2134     join[i][joinSize] = mesh->supports[off+joinSize];
2135   }
2136   /* Check each successive support */
2137   for (p = 1; p < numPoints; ++p) {
2138     PetscInt newJoinSize = 0;
2139 
2140     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2141     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2142     for (c = 0; c < dof; ++c) {
2143       const PetscInt point = mesh->supports[off+c];
2144 
2145       for (m = 0; m < joinSize; ++m) {
2146         if (point == join[i][m]) {
2147           join[1-i][newJoinSize++] = point;
2148           break;
2149         }
2150       }
2151     }
2152     joinSize = newJoinSize;
2153     i        = 1-i;
2154   }
2155   *numCoveredPoints = joinSize;
2156   *coveredPoints    = join[i];
2157   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2158   PetscFunctionReturn(0);
2159 }
2160 
2161 #undef __FUNCT__
2162 #define __FUNCT__ "DMPlexRestoreJoin"
2163 /*@C
2164   DMPlexRestoreJoin - Restore an array for the join of the set of points
2165 
2166   Not Collective
2167 
2168   Input Parameters:
2169 + dm - The DMPlex object
2170 . numPoints - The number of input points for the join
2171 - points - The input points
2172 
2173   Output Parameters:
2174 + numCoveredPoints - The number of points in the join
2175 - coveredPoints - The points in the join
2176 
2177   Level: intermediate
2178 
2179 .keywords: mesh
2180 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2181 @*/
2182 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2183 {
2184   PetscErrorCode ierr;
2185 
2186   PetscFunctionBegin;
2187   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2188   PetscValidPointer(coveredPoints, 4);
2189   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2190   PetscFunctionReturn(0);
2191 }
2192 
2193 #undef __FUNCT__
2194 #define __FUNCT__ "DMPlexGetFullJoin"
2195 /*@C
2196   DMPlexGetFullJoin - Get an array for the join of the set of points
2197 
2198   Not Collective
2199 
2200   Input Parameters:
2201 + dm - The DMPlex object
2202 . numPoints - The number of input points for the join
2203 - points - The input points
2204 
2205   Output Parameters:
2206 + numCoveredPoints - The number of points in the join
2207 - coveredPoints - The points in the join
2208 
2209   Level: intermediate
2210 
2211 .keywords: mesh
2212 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2213 @*/
2214 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2215 {
2216   DM_Plex       *mesh = (DM_Plex*) dm->data;
2217   PetscInt      *offsets, **closures;
2218   PetscInt      *join[2];
2219   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2220   PetscInt       p, d, c, m;
2221   PetscErrorCode ierr;
2222 
2223   PetscFunctionBegin;
2224   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2225   PetscValidPointer(points, 2);
2226   PetscValidPointer(numCoveredPoints, 3);
2227   PetscValidPointer(coveredPoints, 4);
2228 
2229   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2230   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2231   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2232   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2233   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2234   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2235   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2236 
2237   for (p = 0; p < numPoints; ++p) {
2238     PetscInt closureSize;
2239 
2240     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2241 
2242     offsets[p*(depth+2)+0] = 0;
2243     for (d = 0; d < depth+1; ++d) {
2244       PetscInt pStart, pEnd, i;
2245 
2246       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2247       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2248         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2249           offsets[p*(depth+2)+d+1] = i;
2250           break;
2251         }
2252       }
2253       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2254     }
2255     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2256   }
2257   for (d = 0; d < depth+1; ++d) {
2258     PetscInt dof;
2259 
2260     /* Copy in support of first point */
2261     dof = offsets[d+1] - offsets[d];
2262     for (joinSize = 0; joinSize < dof; ++joinSize) {
2263       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2264     }
2265     /* Check each successive cone */
2266     for (p = 1; p < numPoints && joinSize; ++p) {
2267       PetscInt newJoinSize = 0;
2268 
2269       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2270       for (c = 0; c < dof; ++c) {
2271         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2272 
2273         for (m = 0; m < joinSize; ++m) {
2274           if (point == join[i][m]) {
2275             join[1-i][newJoinSize++] = point;
2276             break;
2277           }
2278         }
2279       }
2280       joinSize = newJoinSize;
2281       i        = 1-i;
2282     }
2283     if (joinSize) break;
2284   }
2285   *numCoveredPoints = joinSize;
2286   *coveredPoints    = join[i];
2287   for (p = 0; p < numPoints; ++p) {
2288     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2289   }
2290   ierr = PetscFree(closures);CHKERRQ(ierr);
2291   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2292   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2293   PetscFunctionReturn(0);
2294 }
2295 
2296 #undef __FUNCT__
2297 #define __FUNCT__ "DMPlexGetMeet"
2298 /*@C
2299   DMPlexGetMeet - Get an array for the meet of the set of points
2300 
2301   Not Collective
2302 
2303   Input Parameters:
2304 + dm - The DMPlex object
2305 . numPoints - The number of input points for the meet
2306 - points - The input points
2307 
2308   Output Parameters:
2309 + numCoveredPoints - The number of points in the meet
2310 - coveredPoints - The points in the meet
2311 
2312   Level: intermediate
2313 
2314   Note: Currently, this is restricted to a single level meet
2315 
2316 .keywords: mesh
2317 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2318 @*/
2319 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2320 {
2321   DM_Plex       *mesh = (DM_Plex*) dm->data;
2322   PetscInt      *meet[2];
2323   PetscInt       meetSize, i = 0;
2324   PetscInt       dof, off, p, c, m;
2325   PetscErrorCode ierr;
2326 
2327   PetscFunctionBegin;
2328   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2329   PetscValidPointer(points, 2);
2330   PetscValidPointer(numCoveringPoints, 3);
2331   PetscValidPointer(coveringPoints, 4);
2332   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2333   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2334   /* Copy in cone of first point */
2335   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2336   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2337   for (meetSize = 0; meetSize < dof; ++meetSize) {
2338     meet[i][meetSize] = mesh->cones[off+meetSize];
2339   }
2340   /* Check each successive cone */
2341   for (p = 1; p < numPoints; ++p) {
2342     PetscInt newMeetSize = 0;
2343 
2344     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2345     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2346     for (c = 0; c < dof; ++c) {
2347       const PetscInt point = mesh->cones[off+c];
2348 
2349       for (m = 0; m < meetSize; ++m) {
2350         if (point == meet[i][m]) {
2351           meet[1-i][newMeetSize++] = point;
2352           break;
2353         }
2354       }
2355     }
2356     meetSize = newMeetSize;
2357     i        = 1-i;
2358   }
2359   *numCoveringPoints = meetSize;
2360   *coveringPoints    = meet[i];
2361   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2362   PetscFunctionReturn(0);
2363 }
2364 
2365 #undef __FUNCT__
2366 #define __FUNCT__ "DMPlexRestoreMeet"
2367 /*@C
2368   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2369 
2370   Not Collective
2371 
2372   Input Parameters:
2373 + dm - The DMPlex object
2374 . numPoints - The number of input points for the meet
2375 - points - The input points
2376 
2377   Output Parameters:
2378 + numCoveredPoints - The number of points in the meet
2379 - coveredPoints - The points in the meet
2380 
2381   Level: intermediate
2382 
2383 .keywords: mesh
2384 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2385 @*/
2386 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2387 {
2388   PetscErrorCode ierr;
2389 
2390   PetscFunctionBegin;
2391   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2392   PetscValidPointer(coveredPoints, 4);
2393   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2394   PetscFunctionReturn(0);
2395 }
2396 
2397 #undef __FUNCT__
2398 #define __FUNCT__ "DMPlexGetFullMeet"
2399 /*@C
2400   DMPlexGetFullMeet - Get an array for the meet of the set of points
2401 
2402   Not Collective
2403 
2404   Input Parameters:
2405 + dm - The DMPlex object
2406 . numPoints - The number of input points for the meet
2407 - points - The input points
2408 
2409   Output Parameters:
2410 + numCoveredPoints - The number of points in the meet
2411 - coveredPoints - The points in the meet
2412 
2413   Level: intermediate
2414 
2415 .keywords: mesh
2416 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2417 @*/
2418 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2419 {
2420   DM_Plex       *mesh = (DM_Plex*) dm->data;
2421   PetscInt      *offsets, **closures;
2422   PetscInt      *meet[2];
2423   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2424   PetscInt       p, h, c, m;
2425   PetscErrorCode ierr;
2426 
2427   PetscFunctionBegin;
2428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2429   PetscValidPointer(points, 2);
2430   PetscValidPointer(numCoveredPoints, 3);
2431   PetscValidPointer(coveredPoints, 4);
2432 
2433   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2434   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2435   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2436   maxSize = PetscPowInt(mesh->maxConeSize,height);
2437   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2438   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2439 
2440   for (p = 0; p < numPoints; ++p) {
2441     PetscInt closureSize;
2442 
2443     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2444 
2445     offsets[p*(height+2)+0] = 0;
2446     for (h = 0; h < height+1; ++h) {
2447       PetscInt pStart, pEnd, i;
2448 
2449       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2450       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2451         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2452           offsets[p*(height+2)+h+1] = i;
2453           break;
2454         }
2455       }
2456       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2457     }
2458     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2459   }
2460   for (h = 0; h < height+1; ++h) {
2461     PetscInt dof;
2462 
2463     /* Copy in cone of first point */
2464     dof = offsets[h+1] - offsets[h];
2465     for (meetSize = 0; meetSize < dof; ++meetSize) {
2466       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2467     }
2468     /* Check each successive cone */
2469     for (p = 1; p < numPoints && meetSize; ++p) {
2470       PetscInt newMeetSize = 0;
2471 
2472       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2473       for (c = 0; c < dof; ++c) {
2474         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2475 
2476         for (m = 0; m < meetSize; ++m) {
2477           if (point == meet[i][m]) {
2478             meet[1-i][newMeetSize++] = point;
2479             break;
2480           }
2481         }
2482       }
2483       meetSize = newMeetSize;
2484       i        = 1-i;
2485     }
2486     if (meetSize) break;
2487   }
2488   *numCoveredPoints = meetSize;
2489   *coveredPoints    = meet[i];
2490   for (p = 0; p < numPoints; ++p) {
2491     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2492   }
2493   ierr = PetscFree(closures);CHKERRQ(ierr);
2494   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2495   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2496   PetscFunctionReturn(0);
2497 }
2498 
2499 #undef __FUNCT__
2500 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2501 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2502 {
2503   MPI_Comm       comm = ((PetscObject) dm)->comm;
2504   PetscInt       cellDim;
2505   PetscErrorCode ierr;
2506 
2507   PetscFunctionBegin;
2508   PetscValidPointer(numFaceVertices,3);
2509   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2510   switch (cellDim) {
2511   case 0:
2512     *numFaceVertices = 0;
2513     break;
2514   case 1:
2515     *numFaceVertices = 1;
2516     break;
2517   case 2:
2518     switch (numCorners) {
2519     case 3: /* triangle */
2520       *numFaceVertices = 2; /* Edge has 2 vertices */
2521       break;
2522     case 4: /* quadrilateral */
2523       *numFaceVertices = 2; /* Edge has 2 vertices */
2524       break;
2525     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2526       *numFaceVertices = 3; /* Edge has 3 vertices */
2527       break;
2528     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2529       *numFaceVertices = 3; /* Edge has 3 vertices */
2530       break;
2531     default:
2532       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2533     }
2534     break;
2535   case 3:
2536     switch (numCorners) {
2537     case 4: /* tetradehdron */
2538       *numFaceVertices = 3; /* Face has 3 vertices */
2539       break;
2540     case 6: /* tet cohesive cells */
2541       *numFaceVertices = 4; /* Face has 4 vertices */
2542       break;
2543     case 8: /* hexahedron */
2544       *numFaceVertices = 4; /* Face has 4 vertices */
2545       break;
2546     case 9: /* tet cohesive Lagrange cells */
2547       *numFaceVertices = 6; /* Face has 6 vertices */
2548       break;
2549     case 10: /* quadratic tetrahedron */
2550       *numFaceVertices = 6; /* Face has 6 vertices */
2551       break;
2552     case 12: /* hex cohesive Lagrange cells */
2553       *numFaceVertices = 6; /* Face has 6 vertices */
2554       break;
2555     case 18: /* quadratic tet cohesive Lagrange cells */
2556       *numFaceVertices = 6; /* Face has 6 vertices */
2557       break;
2558     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2559       *numFaceVertices = 9; /* Face has 9 vertices */
2560       break;
2561     default:
2562       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2563     }
2564     break;
2565   default:
2566     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2567   }
2568   PetscFunctionReturn(0);
2569 }
2570 
2571 #undef __FUNCT__
2572 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2573 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2574 {
2575   const PetscInt maxFaceCases = 30;
2576   PetscInt       numFaceCases = 0;
2577   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2578   PetscInt      *off, *adj;
2579   PetscInt      *neighborCells, *tmpClosure;
2580   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2581   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2582   PetscErrorCode ierr;
2583 
2584   PetscFunctionBegin;
2585   /* For parallel partitioning, I think you have to communicate supports */
2586   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2587   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2588   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2589   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2590   if (cEnd - cStart == 0) {
2591     if (numVertices) *numVertices = 0;
2592     if (offsets)   *offsets   = PETSC_NULL;
2593     if (adjacency) *adjacency = PETSC_NULL;
2594     PetscFunctionReturn(0);
2595   }
2596   numCells = cEnd - cStart;
2597   /* Setup face recognition */
2598   if (depth == 1) {
2599     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 */
2600 
2601     for (c = cStart; c < cEnd; ++c) {
2602       PetscInt corners;
2603 
2604       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2605       if (!cornersSeen[corners]) {
2606         PetscInt nFV;
2607 
2608         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2609         cornersSeen[corners] = 1;
2610 
2611         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2612 
2613         numFaceVertices[numFaceCases++] = nFV;
2614       }
2615     }
2616   }
2617   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2618   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2619   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2620   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2621   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2622   /* Count neighboring cells */
2623   for (cell = cStart; cell < cEnd; ++cell) {
2624     PetscInt numNeighbors = maxNeighbors, n;
2625 
2626     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2627     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2628     for (n = 0; n < numNeighbors; ++n) {
2629       PetscInt        cellPair[2];
2630       PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2631       PetscInt        meetSize = 0;
2632       const PetscInt *meet    = PETSC_NULL;
2633 
2634       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2635       if (cellPair[0] == cellPair[1]) continue;
2636       if (!found) {
2637         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2638         if (meetSize) {
2639           PetscInt f;
2640 
2641           for (f = 0; f < numFaceCases; ++f) {
2642             if (numFaceVertices[f] == meetSize) {
2643               found = PETSC_TRUE;
2644               break;
2645             }
2646           }
2647         }
2648         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2649       }
2650       if (found) ++off[cell-cStart+1];
2651     }
2652   }
2653   /* Prefix sum */
2654   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2655 
2656   if (adjacency) {
2657     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2658     /* Get neighboring cells */
2659     for (cell = cStart; cell < cEnd; ++cell) {
2660       PetscInt numNeighbors = maxNeighbors, n;
2661       PetscInt cellOffset   = 0;
2662 
2663       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2664       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2665       for (n = 0; n < numNeighbors; ++n) {
2666         PetscInt        cellPair[2];
2667         PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2668         PetscInt        meetSize = 0;
2669         const PetscInt *meet    = PETSC_NULL;
2670 
2671         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2672         if (cellPair[0] == cellPair[1]) continue;
2673         if (!found) {
2674           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2675           if (meetSize) {
2676             PetscInt f;
2677 
2678             for (f = 0; f < numFaceCases; ++f) {
2679               if (numFaceVertices[f] == meetSize) {
2680                 found = PETSC_TRUE;
2681                 break;
2682               }
2683             }
2684           }
2685           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2686         }
2687         if (found) {
2688           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2689           ++cellOffset;
2690         }
2691       }
2692     }
2693   }
2694   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2695   if (numVertices) *numVertices = numCells;
2696   if (offsets)   *offsets   = off;
2697   if (adjacency) *adjacency = adj;
2698   PetscFunctionReturn(0);
2699 }
2700 
2701 #if defined(PETSC_HAVE_CHACO)
2702 #if defined(PETSC_HAVE_UNISTD_H)
2703 #include <unistd.h>
2704 #endif
2705 /* Chaco does not have an include file */
2706 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2707                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2708                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2709                        int mesh_dims[3], double *goal, int global_method, int local_method,
2710                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2711 
2712 extern int FREE_GRAPH;
2713 
2714 #undef __FUNCT__
2715 #define __FUNCT__ "DMPlexPartition_Chaco"
2716 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2717 {
2718   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2719   MPI_Comm       comm           = ((PetscObject) dm)->comm;
2720   int            nvtxs          = numVertices; /* number of vertices in full graph */
2721   int           *vwgts          = NULL;   /* weights for all vertices */
2722   float         *ewgts          = NULL;   /* weights for all edges */
2723   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2724   char          *outassignname  = NULL;   /*  name of assignment output file */
2725   char          *outfilename    = NULL;   /* output file name */
2726   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2727   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2728   int            mesh_dims[3];            /* dimensions of mesh of processors */
2729   double        *goal          = NULL;    /* desired set sizes for each set */
2730   int            global_method = 1;       /* global partitioning algorithm */
2731   int            local_method  = 1;       /* local partitioning algorithm */
2732   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2733   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2734   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2735   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2736   long           seed          = 123636512; /* for random graph mutations */
2737   short int     *assignment;              /* Output partition */
2738   int            fd_stdout, fd_pipe[2];
2739   PetscInt      *points;
2740   PetscMPIInt    commSize;
2741   int            i, v, p;
2742   PetscErrorCode ierr;
2743 
2744   PetscFunctionBegin;
2745   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2746   if (!numVertices) {
2747     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2748     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2749     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2750     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2751     PetscFunctionReturn(0);
2752   }
2753   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2754   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2755 
2756   if (global_method == INERTIAL_METHOD) {
2757     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2758     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2759   }
2760   mesh_dims[0] = commSize;
2761   mesh_dims[1] = 1;
2762   mesh_dims[2] = 1;
2763   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2764   /* Chaco outputs to stdout. We redirect this to a buffer. */
2765   /* TODO: check error codes for UNIX calls */
2766 #if defined(PETSC_HAVE_UNISTD_H)
2767   {
2768     int piperet;
2769     piperet = pipe(fd_pipe);
2770     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2771     fd_stdout = dup(1);
2772     close(1);
2773     dup2(fd_pipe[1], 1);
2774   }
2775 #endif
2776   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2777                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2778                    vmax, ndims, eigtol, seed);
2779 #if defined(PETSC_HAVE_UNISTD_H)
2780   {
2781     char msgLog[10000];
2782     int  count;
2783 
2784     fflush(stdout);
2785     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2786     if (count < 0) count = 0;
2787     msgLog[count] = 0;
2788     close(1);
2789     dup2(fd_stdout, 1);
2790     close(fd_stdout);
2791     close(fd_pipe[0]);
2792     close(fd_pipe[1]);
2793     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2794   }
2795 #endif
2796   /* Convert to PetscSection+IS */
2797   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2798   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2799   for (v = 0; v < nvtxs; ++v) {
2800     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2801   }
2802   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2803   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2804   for (p = 0, i = 0; p < commSize; ++p) {
2805     for (v = 0; v < nvtxs; ++v) {
2806       if (assignment[v] == p) points[i++] = v;
2807     }
2808   }
2809   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2810   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2811   if (global_method == INERTIAL_METHOD) {
2812     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2813   }
2814   ierr = PetscFree(assignment);CHKERRQ(ierr);
2815   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2816   PetscFunctionReturn(0);
2817 }
2818 #endif
2819 
2820 #if defined(PETSC_HAVE_PARMETIS)
2821 #undef __FUNCT__
2822 #define __FUNCT__ "DMPlexPartition_ParMetis"
2823 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2824 {
2825   PetscFunctionBegin;
2826   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2827   PetscFunctionReturn(0);
2828 }
2829 #endif
2830 
2831 #undef __FUNCT__
2832 #define __FUNCT__ "DMPlexEnlargePartition"
2833 /* Expand the partition by BFS on the adjacency graph */
2834 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2835 {
2836   PetscHashI      h;
2837   const PetscInt *points;
2838   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2839   PetscInt        pStart, pEnd, part, q;
2840   PetscErrorCode  ierr;
2841 
2842   PetscFunctionBegin;
2843   PetscHashICreate(h);
2844   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2845   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2846   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2847   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2848   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2849   for (part = pStart; part < pEnd; ++part) {
2850     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2851 
2852     PetscHashIClear(h);
2853     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2854     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2855     /* Add all existing points to h */
2856     for (p = 0; p < numPoints; ++p) {
2857       const PetscInt point = points[off+p];
2858       PetscHashIAdd(h, point, 1);
2859     }
2860     PetscHashISize(h, nP);
2861     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2862     /* Add all points in next BFS level */
2863     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2864     for (p = 0; p < numPoints; ++p) {
2865       const PetscInt point = points[off+p];
2866       PetscInt       s     = start[point], e = start[point+1], a;
2867 
2868       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2869     }
2870     PetscHashISize(h, numNewPoints);
2871     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2872     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2873     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2874     totPoints += numNewPoints;
2875   }
2876   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2877   PetscHashIDestroy(h);
2878   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2879   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2880   for (part = pStart, q = 0; part < pEnd; ++part) {
2881     PetscInt numPoints, p;
2882 
2883     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2884     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2885     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2886   }
2887   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2888   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2889   PetscFunctionReturn(0);
2890 }
2891 
2892 #undef __FUNCT__
2893 #define __FUNCT__ "DMPlexCreatePartition"
2894 /*
2895   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2896 
2897   Collective on DM
2898 
2899   Input Parameters:
2900   + dm - The DM
2901   . height - The height for points in the partition
2902   - enlarge - Expand each partition with neighbors
2903 
2904   Output Parameters:
2905   + partSection - The PetscSection giving the division of points by partition
2906   . partition - The list of points by partition
2907   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2908   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2909 
2910   Level: developer
2911 
2912 .seealso DMPlexDistribute()
2913 */
2914 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2915 {
2916   PetscMPIInt    size;
2917   PetscErrorCode ierr;
2918 
2919   PetscFunctionBegin;
2920   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2921 
2922   *origPartSection = PETSC_NULL;
2923   *origPartition   = PETSC_NULL;
2924   if (size == 1) {
2925     PetscInt *points;
2926     PetscInt  cStart, cEnd, c;
2927 
2928     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2929     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2930     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2931     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2932     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2933     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2934     for (c = cStart; c < cEnd; ++c) points[c] = c;
2935     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2936     PetscFunctionReturn(0);
2937   }
2938   if (height == 0) {
2939     PetscInt  numVertices;
2940     PetscInt *start     = PETSC_NULL;
2941     PetscInt *adjacency = PETSC_NULL;
2942 
2943     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2944     if (1) {
2945 #if defined(PETSC_HAVE_CHACO)
2946       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2947 #endif
2948     } else {
2949 #if defined(PETSC_HAVE_PARMETIS)
2950       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2951 #endif
2952     }
2953     if (enlarge) {
2954       *origPartSection = *partSection;
2955       *origPartition   = *partition;
2956 
2957       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2958     }
2959     ierr = PetscFree(start);CHKERRQ(ierr);
2960     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2961 # if 0
2962   } else if (height == 1) {
2963     /* Build the dual graph for faces and partition the hypergraph */
2964     PetscInt numEdges;
2965 
2966     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2967     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2968     destroyCSR(numEdges, start, adjacency);
2969 #endif
2970   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2971   PetscFunctionReturn(0);
2972 }
2973 
2974 #undef __FUNCT__
2975 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2976 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2977 {
2978   /* const PetscInt  height = 0; */
2979   const PetscInt *partArray;
2980   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2981   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2982   PetscErrorCode  ierr;
2983 
2984   PetscFunctionBegin;
2985   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2986   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2987   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2988   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2989   for (rank = rStart; rank < rEnd; ++rank) {
2990     PetscInt partSize = 0;
2991     PetscInt numPoints, offset, p;
2992 
2993     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2994     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2995     for (p = 0; p < numPoints; ++p) {
2996       PetscInt  point   = partArray[offset+p], closureSize, c;
2997       PetscInt *closure = PETSC_NULL;
2998 
2999       /* TODO Include support for height > 0 case */
3000       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3001       /* Merge into existing points */
3002       if (partSize+closureSize > maxPartSize) {
3003         PetscInt *tmpPoints;
3004 
3005         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3006         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3007         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3008         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3009 
3010         partPoints = tmpPoints;
3011       }
3012       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3013       partSize += closureSize;
3014 
3015       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3016       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3017     }
3018     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3019   }
3020   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3021   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3022   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3023 
3024   for (rank = rStart; rank < rEnd; ++rank) {
3025     PetscInt partSize = 0, newOffset;
3026     PetscInt numPoints, offset, p;
3027 
3028     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3029     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3030     for (p = 0; p < numPoints; ++p) {
3031       PetscInt  point   = partArray[offset+p], closureSize, c;
3032       PetscInt *closure = PETSC_NULL;
3033 
3034       /* TODO Include support for height > 0 case */
3035       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3036       /* Merge into existing points */
3037       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3038       partSize += closureSize;
3039 
3040       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3041       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3042     }
3043     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3044     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3045   }
3046   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3047   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3048   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3049   PetscFunctionReturn(0);
3050 }
3051 
3052 #undef __FUNCT__
3053 #define __FUNCT__ "DMPlexDistributeField"
3054 /*
3055   Input Parameters:
3056 . originalSection
3057 , originalVec
3058 
3059   Output Parameters:
3060 . newSection
3061 . newVec
3062 */
3063 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3064 {
3065   PetscSF        fieldSF;
3066   PetscInt      *remoteOffsets, fieldSize;
3067   PetscScalar   *originalValues, *newValues;
3068   PetscErrorCode ierr;
3069 
3070   PetscFunctionBegin;
3071   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3072 
3073   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3074   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3075   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3076 
3077   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3078   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3079   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3080   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3081   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3082   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3083   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3084   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3085   PetscFunctionReturn(0);
3086 }
3087 
3088 #undef __FUNCT__
3089 #define __FUNCT__ "DMPlexDistribute"
3090 /*@C
3091   DMPlexDistribute - Distributes the mesh and any associated sections.
3092 
3093   Not Collective
3094 
3095   Input Parameter:
3096 + dm  - The original DMPlex object
3097 . partitioner - The partitioning package, or NULL for the default
3098 - overlap - The overlap of partitions, 0 is the default
3099 
3100   Output Parameter:
3101 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3102 
3103   Note: If the mesh was not distributed, the return value is PETSC_NULL
3104 
3105   Level: intermediate
3106 
3107 .keywords: mesh, elements
3108 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3109 @*/
3110 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3111 {
3112   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3113   MPI_Comm               comm   = ((PetscObject) dm)->comm;
3114   const PetscInt         height = 0;
3115   PetscInt               dim, numRemoteRanks;
3116   IS                     origCellPart,        cellPart,        part;
3117   PetscSection           origCellPartSection, cellPartSection, partSection;
3118   PetscSFNode           *remoteRanks;
3119   PetscSF                partSF, pointSF, coneSF;
3120   ISLocalToGlobalMapping renumbering;
3121   PetscSection           originalConeSection, newConeSection;
3122   PetscInt              *remoteOffsets;
3123   PetscInt              *cones, *newCones, newConesSize;
3124   PetscBool              flg;
3125   PetscMPIInt            rank, numProcs, p;
3126   PetscErrorCode         ierr;
3127 
3128   PetscFunctionBegin;
3129   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3130   PetscValidPointer(dmParallel,4);
3131 
3132   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3133   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3134   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3135 
3136   *dmParallel = PETSC_NULL;
3137   if (numProcs == 1) PetscFunctionReturn(0);
3138 
3139   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3140   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3141   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3142   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3143   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3144   if (!rank) numRemoteRanks = numProcs;
3145   else       numRemoteRanks = 0;
3146   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3147   for (p = 0; p < numRemoteRanks; ++p) {
3148     remoteRanks[p].rank  = p;
3149     remoteRanks[p].index = 0;
3150   }
3151   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3152   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3153   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3154   if (flg) {
3155     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3156     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3157     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3158     if (origCellPart) {
3159       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3160       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3161       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3162     }
3163     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3164   }
3165   /* Close the partition over the mesh */
3166   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3167   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3168   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3169   /* Create new mesh */
3170   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3171   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3172   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3173   pmesh = (DM_Plex*) (*dmParallel)->data;
3174   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3175   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3176   if (flg) {
3177     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3178     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3179     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3180     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3181     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3182     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3183   }
3184   /* Distribute cone section */
3185   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3186   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3187   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3188   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3189   {
3190     PetscInt pStart, pEnd, p;
3191 
3192     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3193     for (p = pStart; p < pEnd; ++p) {
3194       PetscInt coneSize;
3195       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3196       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3197     }
3198   }
3199   /* Communicate and renumber cones */
3200   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3201   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3202   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3203   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3204   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3205   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3206   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3207   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3208   if (flg) {
3209     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3210     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3211     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3212     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3213     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3214   }
3215   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3216   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3217   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3218   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3219   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3220   /* Create supports and stratify sieve */
3221   {
3222     PetscInt pStart, pEnd;
3223 
3224     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3225     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3226   }
3227   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3228   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3229   /* Distribute Coordinates */
3230   {
3231     PetscSection originalCoordSection, newCoordSection;
3232     Vec          originalCoordinates, newCoordinates;
3233     const char  *name;
3234 
3235     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3236     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3237     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3238     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3239     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3240     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3241 
3242     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3243     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3244     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3245   }
3246   /* Distribute labels */
3247   {
3248     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3249     PetscInt numLabels = 0, l;
3250 
3251     /* Bcast number of labels */
3252     while (next) {
3253       ++numLabels; next = next->next;
3254     }
3255     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3256     next = mesh->labels;
3257     for (l = 0; l < numLabels; ++l) {
3258       DMLabel         newLabel;
3259       const PetscInt *partArray;
3260       char           *name;
3261       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3262       PetscMPIInt    *sendcnts     = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3263       PetscInt        nameSize, s, p;
3264       PetscBool       isdepth;
3265       size_t          len = 0;
3266 
3267       /* Bcast name (could filter for no points) */
3268       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3269       nameSize = len;
3270       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3271       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3272       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3273       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3274       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3275       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3276       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3277       newLabel->name = name;
3278       /* Bcast numStrata (could filter for no points in stratum) */
3279       if (!rank) newLabel->numStrata = next->numStrata;
3280       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3281       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3282                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3283                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3284       /* Bcast stratumValues (could filter for no points in stratum) */
3285       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3286       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3287       /* Find size on each process and Scatter */
3288       if (!rank) {
3289         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3290         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3291         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3292         for (s = 0; s < next->numStrata; ++s) {
3293           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3294             const PetscInt point = next->points[p];
3295             PetscInt       proc;
3296 
3297             for (proc = 0; proc < numProcs; ++proc) {
3298               PetscInt dof, off, pPart;
3299 
3300               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3301               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3302               for (pPart = off; pPart < off+dof; ++pPart) {
3303                 if (partArray[pPart] == point) {
3304                   ++stratumSizes[proc*next->numStrata+s];
3305                   break;
3306                 }
3307               }
3308             }
3309           }
3310         }
3311         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3312       }
3313       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3314       /* Calculate stratumOffsets */
3315       newLabel->stratumOffsets[0] = 0;
3316       for (s = 0; s < newLabel->numStrata; ++s) {
3317         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3318       }
3319       /* Pack points and Scatter */
3320       if (!rank) {
3321         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3322         displs[0] = 0;
3323         for (p = 0; p < numProcs; ++p) {
3324           sendcnts[p] = 0;
3325           for (s = 0; s < next->numStrata; ++s) {
3326             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3327           }
3328           offsets[p]  = displs[p];
3329           displs[p+1] = displs[p] + sendcnts[p];
3330         }
3331         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3332         for (s = 0; s < next->numStrata; ++s) {
3333           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3334             const PetscInt point = next->points[p];
3335             PetscInt       proc;
3336 
3337             for (proc = 0; proc < numProcs; ++proc) {
3338               PetscInt dof, off, pPart;
3339 
3340               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3341               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3342               for (pPart = off; pPart < off+dof; ++pPart) {
3343                 if (partArray[pPart] == point) {
3344                   points[offsets[proc]++] = point;
3345                   break;
3346                 }
3347               }
3348             }
3349           }
3350         }
3351       }
3352       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3353       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3354       ierr = PetscFree(points);CHKERRQ(ierr);
3355       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3356       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3357       /* Renumber points */
3358       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3359       /* Sort points */
3360       for (s = 0; s < newLabel->numStrata; ++s) {
3361         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3362       }
3363       /* Insert into list */
3364       if (newNext) newNext->next = newLabel;
3365       else pmesh->labels = newLabel;
3366       newNext = newLabel;
3367       if (!rank) next = next->next;
3368     }
3369   }
3370   /* Cleanup Partition */
3371   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3372   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3373   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3374   ierr = ISDestroy(&part);CHKERRQ(ierr);
3375   /* Create point SF for parallel mesh */
3376   {
3377     const PetscInt *leaves;
3378     PetscSFNode    *remotePoints, *rowners, *lowners;
3379     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3380     PetscInt        pStart, pEnd;
3381 
3382     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3383     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3384     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3385     for (p=0; p<numRoots; p++) {
3386       rowners[p].rank  = -1;
3387       rowners[p].index = -1;
3388     }
3389     if (origCellPart) {
3390       /* Make sure cells in the original partition are not assigned to other procs */
3391       const PetscInt *origCells;
3392 
3393       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3394       for (p = 0; p < numProcs; ++p) {
3395         PetscInt dof, off, d;
3396 
3397         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3398         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3399         for (d = off; d < off+dof; ++d) {
3400           rowners[origCells[d]].rank = p;
3401         }
3402       }
3403       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3404     }
3405     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3406     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3407 
3408     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3409     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3410     for (p = 0; p < numLeaves; ++p) {
3411       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3412         lowners[p].rank  = rank;
3413         lowners[p].index = leaves ? leaves[p] : p;
3414       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3415         lowners[p].rank  = -2;
3416         lowners[p].index = -2;
3417       }
3418     }
3419     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3420       rowners[p].rank  = -3;
3421       rowners[p].index = -3;
3422     }
3423     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3424     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3425     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3426     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3427     for (p = 0; p < numLeaves; ++p) {
3428       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3429       if (lowners[p].rank != rank) ++numGhostPoints;
3430     }
3431     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3432     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3433     for (p = 0, gp = 0; p < numLeaves; ++p) {
3434       if (lowners[p].rank != rank) {
3435         ghostPoints[gp]        = leaves ? leaves[p] : p;
3436         remotePoints[gp].rank  = lowners[p].rank;
3437         remotePoints[gp].index = lowners[p].index;
3438         ++gp;
3439       }
3440     }
3441     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3442     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3443     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3444   }
3445   /* Cleanup */
3446   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3447   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3448   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3449   PetscFunctionReturn(0);
3450 }
3451 
3452 #undef __FUNCT__
3453 #define __FUNCT__ "DMPlexRenumber_Private"
3454 /*
3455   Reasons to renumber:
3456 
3457   1) Permute points, e.g. bandwidth reduction (Renumber)
3458 
3459     a) Must not mix strata
3460 
3461   2) Shift numbers for point insertion (Shift)
3462 
3463     a) Want operation brken into parts so that insertion can be interleaved
3464 
3465   renumbering - An IS which provides the new numbering
3466 */
3467 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3468 {
3469   PetscFunctionBegin;
3470   PetscFunctionReturn(0);
3471 }
3472 
3473 #undef __FUNCT__
3474 #define __FUNCT__ "DMPlexShiftPoint_Private"
3475 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3476 {
3477   if (depth < 0) return p;
3478   /* Cells    */ if (p < depthEnd[depth])   return p;
3479   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3480   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3481   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3482 }
3483 
3484 #undef __FUNCT__
3485 #define __FUNCT__ "DMPlexShiftSizes_Private"
3486 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3487 {
3488   PetscInt      *depthEnd;
3489   PetscInt       depth = 0, d, pStart, pEnd, p;
3490   PetscErrorCode ierr;
3491 
3492   PetscFunctionBegin;
3493   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3494   if (depth < 0) PetscFunctionReturn(0);
3495   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3496   /* Step 1: Expand chart */
3497   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3498   for (d = 0; d <= depth; ++d) {
3499     pEnd += depthShift[d];
3500     ierr  = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3501   }
3502   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3503   /* Step 2: Set cone and support sizes */
3504   for (d = 0; d <= depth; ++d) {
3505     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3506     for (p = pStart; p < pEnd; ++p) {
3507       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3508       PetscInt size;
3509 
3510       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3511       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3512       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3513       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3514     }
3515   }
3516   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3517   PetscFunctionReturn(0);
3518 }
3519 
3520 #undef __FUNCT__
3521 #define __FUNCT__ "DMPlexShiftPoints_Private"
3522 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3523 {
3524   PetscInt      *depthEnd, *newpoints;
3525   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3526   PetscErrorCode ierr;
3527 
3528   PetscFunctionBegin;
3529   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3530   if (depth < 0) PetscFunctionReturn(0);
3531   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3532   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3533   for (d = 0; d <= depth; ++d) {
3534     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3535   }
3536   /* Step 5: Set cones and supports */
3537   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3538   for (p = pStart; p < pEnd; ++p) {
3539     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3540     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3541 
3542     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3543     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3544     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3545     for (i = 0; i < size; ++i) {
3546       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3547     }
3548     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3549     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3550     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3551     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3552     for (i = 0; i < size; ++i) {
3553       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3554     }
3555     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3556   }
3557   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3558   PetscFunctionReturn(0);
3559 }
3560 
3561 #undef __FUNCT__
3562 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3563 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3564 {
3565   PetscSection   coordSection, newCoordSection;
3566   Vec            coordinates, newCoordinates;
3567   PetscScalar   *coords, *newCoords;
3568   PetscInt      *depthEnd, coordSize;
3569   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3570   PetscErrorCode ierr;
3571 
3572   PetscFunctionBegin;
3573   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3574   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3575   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3576   for (d = 0; d <= depth; ++d) {
3577     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3578   }
3579   /* Step 8: Convert coordinates */
3580   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3581   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3582   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3583   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3584   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3585   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3586   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3587   for (v = vStartNew; v < vEndNew; ++v) {
3588     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3589     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3590   }
3591   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3592   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3593   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3594   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3595   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3596   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3597   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3598   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3599   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3600   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3601   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3602   for (v = vStart; v < vEnd; ++v) {
3603     PetscInt dof, off, noff, d;
3604 
3605     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3606     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3607     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3608     for (d = 0; d < dof; ++d) {
3609       newCoords[noff+d] = coords[off+d];
3610     }
3611   }
3612   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3613   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3614   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3615   PetscFunctionReturn(0);
3616 }
3617 
3618 #undef __FUNCT__
3619 #define __FUNCT__ "DMPlexShiftSF_Private"
3620 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3621 {
3622   PetscInt          *depthEnd;
3623   PetscInt           depth = 0, d;
3624   PetscSF            sfPoint, sfPointNew;
3625   const PetscSFNode *remotePoints;
3626   PetscSFNode       *gremotePoints;
3627   const PetscInt    *localPoints;
3628   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3629   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3630   PetscMPIInt        numProcs;
3631   PetscErrorCode     ierr;
3632 
3633   PetscFunctionBegin;
3634   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3635   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3636   for (d = 0; d <= depth; ++d) {
3637     totShift += depthShift[d];
3638     ierr      = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3639   }
3640   /* Step 9: Convert pointSF */
3641   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3642   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3643   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3644   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3645   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3646   if (numRoots >= 0) {
3647     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3648     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3649     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3650     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3651     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3652     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3653     for (l = 0; l < numLeaves; ++l) {
3654       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3655       gremotePoints[l].rank  = remotePoints[l].rank;
3656       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3657     }
3658     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3659     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3660   }
3661   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3662   PetscFunctionReturn(0);
3663 }
3664 
3665 #undef __FUNCT__
3666 #define __FUNCT__ "DMPlexShiftLabels_Private"
3667 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3668 {
3669   PetscSF            sfPoint;
3670   DMLabel            vtkLabel, ghostLabel;
3671   PetscInt          *depthEnd;
3672   const PetscSFNode *leafRemote;
3673   const PetscInt    *leafLocal;
3674   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3675   PetscMPIInt        rank;
3676   PetscErrorCode     ierr;
3677 
3678   PetscFunctionBegin;
3679   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3680   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3681   for (d = 0; d <= depth; ++d) {
3682     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3683   }
3684   /* Step 10: Convert labels */
3685   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3686   for (l = 0; l < numLabels; ++l) {
3687     DMLabel         label, newlabel;
3688     const char     *lname;
3689     PetscBool       isDepth;
3690     IS              valueIS;
3691     const PetscInt *values;
3692     PetscInt        numValues, val;
3693 
3694     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3695     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3696     if (isDepth) continue;
3697     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3698     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3699     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3700     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3701     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3702     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3703     for (val = 0; val < numValues; ++val) {
3704       IS              pointIS;
3705       const PetscInt *points;
3706       PetscInt        numPoints, p;
3707 
3708       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3709       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3710       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3711       for (p = 0; p < numPoints; ++p) {
3712         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3713 
3714         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3715       }
3716       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3717       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3718     }
3719     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3720     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3721   }
3722   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3723   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3724   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3725   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3726   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3727   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3728   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3729   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3730   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3731   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3732   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3733     for (; c < leafLocal[l] && c < cEnd; ++c) {
3734       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3735     }
3736     if (leafLocal[l] >= cEnd) break;
3737     if (leafRemote[l].rank == rank) {
3738       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3739     } else {
3740       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3741     }
3742   }
3743   for (; c < cEnd; ++c) {
3744     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3745   }
3746   if (0) {
3747     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3748     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3749     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3750   }
3751   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3752   for (f = fStart; f < fEnd; ++f) {
3753     PetscInt numCells;
3754 
3755     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3756     if (numCells < 2) {
3757       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3758     } else {
3759       const PetscInt *cells = PETSC_NULL;
3760       PetscInt        vA, vB;
3761 
3762       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3763       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3764       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3765       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3766     }
3767   }
3768   if (0) {
3769     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3770     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3771     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3772   }
3773   PetscFunctionReturn(0);
3774 }
3775 
3776 #undef __FUNCT__
3777 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3778 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3779 {
3780   DMLabel         label;
3781   IS              valueIS;
3782   const PetscInt *values;
3783   PetscInt       *depthShift;
3784   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3785   PetscErrorCode  ierr;
3786 
3787   PetscFunctionBegin;
3788   /* Count ghost cells */
3789   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3790   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3791   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3792   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3793 
3794   *numGhostCells = 0;
3795   for (fs = 0; fs < numFS; ++fs) {
3796     PetscInt numBdFaces;
3797 
3798     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3799 
3800     *numGhostCells += numBdFaces;
3801   }
3802   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3803   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3804   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3805   if (depth >= 0) depthShift[depth] = *numGhostCells;
3806   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3807   /* Step 3: Set cone/support sizes for new points */
3808   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3809   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3810     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3811   }
3812   for (fs = 0; fs < numFS; ++fs) {
3813     IS              faceIS;
3814     const PetscInt *faces;
3815     PetscInt        numFaces, f;
3816 
3817     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3818     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3819     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3820     for (f = 0; f < numFaces; ++f) {
3821       PetscInt size;
3822 
3823       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3824       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3825       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3826     }
3827     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3828     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3829   }
3830   /* Step 4: Setup ghosted DM */
3831   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3832   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3833   /* Step 6: Set cones and supports for new points */
3834   ghostCell = cEnd;
3835   for (fs = 0; fs < numFS; ++fs) {
3836     IS              faceIS;
3837     const PetscInt *faces;
3838     PetscInt        numFaces, f;
3839 
3840     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3841     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3842     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3843     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3844       PetscInt newFace = faces[f] + *numGhostCells;
3845 
3846       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3847       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3848     }
3849     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3850     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3851   }
3852   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3853   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3854   /* Step 7: Stratify */
3855   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3856   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3857   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3858   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3859   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3860   PetscFunctionReturn(0);
3861 }
3862 
3863 #undef __FUNCT__
3864 #define __FUNCT__ "DMPlexConstructGhostCells"
3865 /*@C
3866   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3867 
3868   Collective on dm
3869 
3870   Input Parameters:
3871 + dm - The original DM
3872 - labelName - The label specifying the boundary faces (this could be auto-generated)
3873 
3874   Output Parameters:
3875 + numGhostCells - The number of ghost cells added to the DM
3876 - dmGhosted - The new DM
3877 
3878   Level: developer
3879 
3880 .seealso: DMCreate()
3881 */
3882 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3883 {
3884   DM             gdm;
3885   PetscInt       dim;
3886   PetscErrorCode ierr;
3887 
3888   PetscFunctionBegin;
3889   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3890   PetscValidPointer(numGhostCells, 3);
3891   PetscValidPointer(dmGhosted, 4);
3892   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3893   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3894   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3895   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3896   switch (dim) {
3897   case 2:
3898     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3899     break;
3900   default:
3901     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3902   }
3903   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3904   *dmGhosted = gdm;
3905   PetscFunctionReturn(0);
3906 }
3907 
3908 #undef __FUNCT__
3909 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3910 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, const char labelName[], DM sdm)
3911 {
3912   MPI_Comm        comm = ((PetscObject) dm)->comm;
3913   DMLabel         label;
3914   IS              valueIS, *pointIS;
3915   const PetscInt *values, **splitPoints;
3916   PetscSection    coordSection;
3917   Vec             coordinates;
3918   PetscScalar    *coords;
3919   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3920   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3921   PetscErrorCode  ierr;
3922 
3923   PetscFunctionBegin;
3924   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3925   /* Count split points and add cohesive cells */
3926   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3927   if (label) {
3928     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3929     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3930     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3931   }
3932   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3933   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3934   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3935   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3936   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3937   for (d = 0; d <= depth; ++d) {
3938     ierr              = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3939     numSplitPoints[d] = 0;
3940     splitPoints[d]    = PETSC_NULL;
3941     pointIS[d]        = PETSC_NULL;
3942   }
3943   for (sp = 0; sp < numSP; ++sp) {
3944     const PetscInt dep = values[sp];
3945 
3946     if ((dep < 0) || (dep > depth)) continue;
3947     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3948     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3949     if (pointIS[dep]) {
3950       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3951       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3952     }
3953   }
3954   if (depth >= 0) {
3955     /* Calculate number of additional points */
3956     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3957     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3958     /* Calculate hybrid bound for each dimension */
3959     pMaxNew[0] += depthShift[depth];
3960     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3961     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3962 
3963     /* Calculate point offset for each dimension */
3964     depthOffset[depth] = 0;
3965     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3966     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3967     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3968   }
3969   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3970   /* Step 3: Set cone/support sizes for new points */
3971   for (dep = 0; dep <= depth; ++dep) {
3972     for (p = 0; p < numSplitPoints[dep]; ++p) {
3973       const PetscInt  oldp   = splitPoints[dep][p];
3974       const PetscInt  newp   = depthOffset[dep] + oldp;
3975       const PetscInt  splitp = pMaxNew[dep] + p;
3976       const PetscInt *support;
3977       PetscInt        coneSize, supportSize, q, e;
3978 
3979       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3980       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3981       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3982       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3983       if (dep == depth-1) {
3984         const PetscInt ccell = pMaxNew[depth] + p;
3985         /* Add cohesive cells, they are prisms */
3986         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3987       } else if (dep == 0) {
3988         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3989 
3990         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3991         /* Split old vertex: Edges in old split faces and new cohesive edge */
3992         for (e = 0, q = 0; e < supportSize; ++e) {
3993           PetscInt val;
3994 
3995           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3996           if ((val == 1) || (val == (shift + 1))) ++q;
3997         }
3998         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3999         /* Split new vertex: Edges in new 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, splitp, q+1);CHKERRQ(ierr);
4007         /* Add cohesive edges */
4008         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4009         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4010       } else if (dep == dim-2) {
4011         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4012         /* Split old edge: Faces in positive side cells and old split faces */
4013         for (e = 0, q = 0; e < supportSize; ++e) {
4014           PetscInt val;
4015 
4016           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4017           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4018         }
4019         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4020         /* Split new edge: Faces in negative side cells and new 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, splitp, q);CHKERRQ(ierr);
4028       }
4029     }
4030   }
4031   /* Step 4: Setup split DM */
4032   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4033   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4034   /* Step 6: Set cones and supports for new points */
4035   for (dep = 0; dep <= depth; ++dep) {
4036     for (p = 0; p < numSplitPoints[dep]; ++p) {
4037       const PetscInt  oldp   = splitPoints[dep][p];
4038       const PetscInt  newp   = depthOffset[dep] + oldp;
4039       const PetscInt  splitp = pMaxNew[dep] + p;
4040       const PetscInt *cone, *support, *ornt;
4041       PetscInt        coneSize, supportSize, q, v, e, s;
4042 
4043       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4044       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4045       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4046       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4047       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4048       if (dep == depth-1) {
4049         const PetscInt  ccell = pMaxNew[depth] + p;
4050         const PetscInt *supportF;
4051 
4052         /* Split face:       copy in old face to new face to start */
4053         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4054         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4055         /* Split old face:   old vertices/edges in cone so no change */
4056         /* Split new face:   new vertices/edges in cone */
4057         for (q = 0; q < coneSize; ++q) {
4058           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4059 
4060           coneNew[2+q] = pMaxNew[dim-2] + v;
4061         }
4062         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4063         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4064         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4065         coneNew[0] = newp;
4066         coneNew[1] = splitp;
4067         for (q = 0; q < coneSize; ++q) {
4068           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4069         }
4070         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4071 
4072 
4073         for (s = 0; s < supportSize; ++s) {
4074           PetscInt val;
4075 
4076           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4077           if (val < 0) {
4078             /* Split old face:   Replace negative side cell with cohesive cell */
4079             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4080           } else {
4081             /* Split new face:   Replace positive side cell with cohesive cell */
4082             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4083           }
4084         }
4085       } else if (dep == 0) {
4086         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4087 
4088         /* Split old vertex: Edges in old split faces and new cohesive edge */
4089         for (e = 0, q = 0; e < supportSize; ++e) {
4090           PetscInt val;
4091 
4092           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4093           if ((val == 1) || (val == (shift + 1))) {
4094             supportNew[q++] = depthOffset[1] + support[e];
4095           }
4096         }
4097         supportNew[q] = cedge;
4098 
4099         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4100         /* Split new vertex: Edges in new split faces and new cohesive edge */
4101         for (e = 0, q = 0; e < supportSize; ++e) {
4102           PetscInt val, edge;
4103 
4104           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4105           if (val == 1) {
4106             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4107             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4108             supportNew[q++] = pMaxNew[1] + edge;
4109           } else if (val == -(shift + 1)) {
4110             supportNew[q++] = depthOffset[1] + support[e];
4111           }
4112         }
4113         supportNew[q] = cedge;
4114         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4115         /* Cohesive edge:    Old and new split vertex, punting on support */
4116         coneNew[0] = newp;
4117         coneNew[1] = splitp;
4118         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4119       } else if (dep == dim-2) {
4120         /* Split old edge:   old vertices in cone so no change */
4121         /* Split new edge:   new vertices in cone */
4122         for (q = 0; q < coneSize; ++q) {
4123           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4124 
4125           coneNew[q] = pMaxNew[dim-3] + v;
4126         }
4127         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4128         /* Split old edge: Faces in positive side cells and old split faces */
4129         for (e = 0, q = 0; e < supportSize; ++e) {
4130           PetscInt val;
4131 
4132           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4133           if ((val == dim-1) || (val == (shift + dim-1))) {
4134             supportNew[q++] = depthOffset[dim-1] + support[e];
4135           }
4136         }
4137         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4138         /* Split new edge: Faces in negative side cells and new split faces */
4139         for(e = 0, q = 0; e < supportSize; ++e) {
4140           PetscInt val, face;
4141 
4142           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4143           if (val == dim-1) {
4144             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4145             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4146             supportNew[q++] = pMaxNew[dim-1] + face;
4147           } else if (val == -(shift + dim-1)) {
4148             supportNew[q++] = depthOffset[dim-1] + support[e];
4149           }
4150         }
4151         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4152       }
4153     }
4154   }
4155   /* Step 6b: Replace split points in negative side cones */
4156   for (sp = 0; sp < numSP; ++sp) {
4157     PetscInt        dep = values[sp];
4158     IS              pIS;
4159     PetscInt        numPoints;
4160     const PetscInt *points;
4161 
4162     if (dep >= 0) continue;
4163     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4164     if (!pIS) continue;
4165     dep  = -dep - shift;
4166     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4167     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4168     for (p = 0; p < numPoints; ++p) {
4169       const PetscInt  oldp = points[p];
4170       const PetscInt  newp = depthOffset[dep] + oldp;
4171       const PetscInt *cone;
4172       PetscInt        coneSize, c;
4173       PetscBool       replaced = PETSC_FALSE;
4174 
4175       /* Negative edge: replace split vertex */
4176       /* Negative cell: replace split face */
4177       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4178       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4179       for (c = 0; c < coneSize; ++c) {
4180         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4181         PetscInt       csplitp, cp, val;
4182 
4183         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4184         if (val == dep-1) {
4185           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4186           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4187           csplitp  = pMaxNew[dep-1] + cp;
4188           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4189           replaced = PETSC_TRUE;
4190         }
4191       }
4192       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4193     }
4194     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4195     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4196   }
4197   /* Step 7: Stratify */
4198   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4199   /* Step 8: Coordinates */
4200   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4201   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4202   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4203   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4204   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4205     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4206     const PetscInt splitp = pMaxNew[0] + v;
4207     PetscInt       dof, off, soff, d;
4208 
4209     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4210     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4211     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4212     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4213   }
4214   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4215   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4216   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4217   /* Step 10: Labels */
4218   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4219   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4220   for (dep = 0; dep <= depth; ++dep) {
4221     for (p = 0; p < numSplitPoints[dep]; ++p) {
4222       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4223       const PetscInt splitp = pMaxNew[dep] + p;
4224       PetscInt       l;
4225 
4226       for (l = 0; l < numLabels; ++l) {
4227         DMLabel     label;
4228         const char *lname;
4229         PetscInt    val;
4230 
4231         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4232         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4233         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4234         if (val >= 0) {
4235           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4236           if (dep == 0) {
4237             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4238             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4239           }
4240         }
4241       }
4242     }
4243   }
4244   for (sp = 0; sp < numSP; ++sp) {
4245     const PetscInt dep = values[sp];
4246 
4247     if ((dep < 0) || (dep > depth)) continue;
4248     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4249     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4250   }
4251   if (label) {
4252     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4253     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4254   }
4255   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4256   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4257   PetscFunctionReturn(0);
4258 }
4259 
4260 #undef __FUNCT__
4261 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4262 /*@C
4263   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4264 
4265   Collective on dm
4266 
4267   Input Parameters:
4268 + dm - The original DM
4269 - labelName - The label specifying the boundary faces (this could be auto-generated)
4270 
4271   Output Parameters:
4272 - dmSplit - The new DM
4273 
4274   Level: developer
4275 
4276 .seealso: DMCreate()
4277 */
4278 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4279 {
4280   DM             sdm;
4281   PetscInt       dim;
4282   PetscErrorCode ierr;
4283 
4284   PetscFunctionBegin;
4285   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4286   PetscValidPointer(dmSplit, 4);
4287   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4288   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4289   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4290   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4291   switch (dim) {
4292   case 2:
4293   case 3:
4294     ierr = DMPlexConstructCohesiveCells_Private(dm, labelName, sdm);CHKERRQ(ierr);
4295     break;
4296   default:
4297     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4298   }
4299   *dmSplit = sdm;
4300   PetscFunctionReturn(0);
4301 }
4302 
4303 #undef __FUNCT__
4304 #define __FUNCT__ "DMLabelCohesiveComplete"
4305 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4306 {
4307   IS              dimIS;
4308   const PetscInt *points;
4309   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4310   PetscErrorCode  ierr;
4311 
4312   PetscFunctionBegin;
4313   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4314   /* Cell orientation for face gives the side of the fault */
4315   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4316   if (!dimIS) PetscFunctionReturn(0);
4317   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4318   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4319   for (p = 0; p < numPoints; ++p) {
4320     const PetscInt *support;
4321     PetscInt        supportSize, s;
4322 
4323     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4324     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4325     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4326     for (s = 0; s < supportSize; ++s) {
4327       const PetscInt *cone, *ornt;
4328       PetscInt        coneSize, c;
4329       PetscBool       pos = PETSC_TRUE;
4330 
4331       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4332       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4333       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4334       for(c = 0; c < coneSize; ++c) {
4335         if (cone[c] == points[p]) {
4336           if (ornt[c] >= 0) {
4337             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4338           } else {
4339             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4340             pos  = PETSC_FALSE;
4341           }
4342           break;
4343         }
4344       }
4345       if (c == coneSize) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4346       /* Put faces touching the fault in the label */
4347       for (c = 0; c < coneSize; ++c) {
4348         const PetscInt point = cone[c];
4349 
4350         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4351         if (val == -1) {
4352           PetscInt *closure = PETSC_NULL;
4353           PetscInt  closureSize, cl;
4354 
4355           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4356           for (cl = 0; cl < closureSize*2; cl += 2) {
4357             const PetscInt clp = closure[cl];
4358 
4359             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4360             if ((val >= 0) && (val < dim-1)) {
4361               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4362               break;
4363             }
4364           }
4365           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4366         }
4367       }
4368     }
4369   }
4370   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4371   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4372   /* Search for other cells/faces/edges connected to the fault by a vertex */
4373   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4374   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4375   if (!dimIS) PetscFunctionReturn(0);
4376   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4377   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4378   for (p = 0; p < numPoints; ++p) {
4379     PetscInt *star = PETSC_NULL;
4380     PetscInt  starSize, s;
4381     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4382 
4383     /* First mark cells connected to the fault */
4384     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4385     while (again) {
4386       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4387       again = 0;
4388       for (s = 0; s < starSize*2; s += 2) {
4389         const PetscInt  point = star[s];
4390         const PetscInt *cone;
4391         PetscInt        coneSize, c;
4392 
4393         if ((point < cStart) || (point >= cEnd)) continue;
4394         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4395         if (val != -1) continue;
4396         again = 2;
4397         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4398         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4399         for (c = 0; c < coneSize; ++c) {
4400           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4401           if (val != -1) {
4402             if (abs(val) < shift) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4403             if (val > 0) {
4404               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4405             } else {
4406               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4407             }
4408             again = 1;
4409             break;
4410           }
4411         }
4412       }
4413     }
4414     /* Classify the rest by cell membership */
4415     for (s = 0; s < starSize*2; s += 2) {
4416       const PetscInt point = star[s];
4417 
4418       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4419       if (val == -1) {
4420         PetscInt  *sstar = PETSC_NULL;
4421         PetscInt   sstarSize, ss;
4422         PetscBool  marked = PETSC_FALSE;
4423 
4424         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4425         for (ss = 0; ss < sstarSize*2; ss += 2) {
4426           const PetscInt spoint = sstar[ss];
4427 
4428           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4429           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4430           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4431           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4432           if (val > 0) {
4433             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4434           } else {
4435             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4436           }
4437           marked = PETSC_TRUE;
4438           break;
4439         }
4440         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4441         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4442       }
4443     }
4444     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4445   }
4446   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4447   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4448   PetscFunctionReturn(0);
4449 }
4450 
4451 #undef __FUNCT__
4452 #define __FUNCT__ "DMPlexInterpolate_2D"
4453 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4454 {
4455   DM             idm;
4456   DM_Plex       *mesh;
4457   PetscHashIJ    edgeTable;
4458   PetscInt      *off;
4459   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4460   PetscInt       numEdges, firstEdge, edge, e;
4461   PetscErrorCode ierr;
4462 
4463   PetscFunctionBegin;
4464   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4465   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4466   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4467   numCells    = cEnd - cStart;
4468   numVertices = vEnd - vStart;
4469   firstEdge   = numCells + numVertices;
4470   numEdges    = 0;
4471   /* Count edges using algorithm from CreateNeighborCSR */
4472   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4473   if (off) {
4474     PetscInt numCorners = 0;
4475 
4476     numEdges = off[numCells]/2;
4477 #if 0
4478     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4479     numEdges += 3*numCells - off[numCells];
4480 #else
4481     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4482     for (c = cStart; c < cEnd; ++c) {
4483       PetscInt coneSize;
4484 
4485       ierr        = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4486       numCorners += coneSize;
4487     }
4488     numEdges += numCorners - off[numCells];
4489 #endif
4490   }
4491 #if 0
4492   /* Check Euler characteristic V - E + F = 1 */
4493   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4494 #endif
4495   /* Create interpolated mesh */
4496   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4497   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4498   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4499   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4500   for (c = 0; c < numCells; ++c) {
4501     PetscInt numCorners;
4502 
4503     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4504     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4505   }
4506   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4507     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4508   }
4509   ierr = DMSetUp(idm);CHKERRQ(ierr);
4510   /* Get edge cones from subsets of cell vertices */
4511   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4512   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4513 
4514   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4515     const PetscInt *cellFaces;
4516     PetscInt        numCellFaces, faceSize, cf;
4517 
4518     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4519     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4520     for (cf = 0; cf < numCellFaces; ++cf) {
4521 #if 1
4522       PetscHashIJKey key;
4523 
4524       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4525       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4526       ierr  = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4527       if (e < 0) {
4528         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4529         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4530         e    = edge++;
4531       }
4532 #else
4533       PetscBool found = PETSC_FALSE;
4534 
4535       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4536       for (e = firstEdge; e < edge; ++e) {
4537         const PetscInt *cone;
4538 
4539         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4540         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4541             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4542           found = PETSC_TRUE;
4543           break;
4544         }
4545       }
4546       if (!found) {
4547         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4548         ++edge;
4549       }
4550 #endif
4551       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4552     }
4553   }
4554   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4555   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4556   ierr = PetscFree(off);CHKERRQ(ierr);
4557   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4558   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4559   mesh = (DM_Plex*) (idm)->data;
4560   /* Orient edges */
4561   for (c = 0; c < numCells; ++c) {
4562     const PetscInt *cone = PETSC_NULL, *cellFaces;
4563     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4564 
4565     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4566     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4567     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4568     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4569     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4570     for (cf = 0; cf < numCellFaces; ++cf) {
4571       const PetscInt *econe = PETSC_NULL;
4572       PetscInt        esize;
4573 
4574       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4575       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4576       if (esize != 2) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4577       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4578         /* Correctly oriented */
4579         mesh->coneOrientations[coff+cf] = 0;
4580       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4581         /* Start at index 1, and reverse orientation */
4582         mesh->coneOrientations[coff+cf] = -(1+1);
4583       }
4584     }
4585   }
4586   *dmInt = idm;
4587   PetscFunctionReturn(0);
4588 }
4589 
4590 #undef __FUNCT__
4591 #define __FUNCT__ "DMPlexInterpolate_3D"
4592 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4593 {
4594   DM             idm, fdm;
4595   DM_Plex       *mesh;
4596   PetscInt      *off;
4597   const PetscInt numCorners = 4;
4598   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4599   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4600   PetscErrorCode ierr;
4601 
4602   PetscFunctionBegin;
4603   {
4604     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4605     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4606     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4607   }
4608   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4609   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4610   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4611   numCells    = cEnd - cStart;
4612   numVertices = vEnd - vStart;
4613   firstFace   = numCells + numVertices;
4614   numFaces    = 0;
4615   /* Count faces using algorithm from CreateNeighborCSR */
4616   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4617   if (off) {
4618     numFaces = off[numCells]/2;
4619     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4620     numFaces += 4*numCells - off[numCells];
4621   }
4622   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4623   firstEdge = firstFace + numFaces;
4624   numEdges  = numVertices + numFaces - numCells - 1;
4625   /* Create interpolated mesh */
4626   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4627   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4628   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4629   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4630   for (c = 0; c < numCells; ++c) {
4631     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4632   }
4633   for (f = firstFace; f < firstFace+numFaces; ++f) {
4634     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4635   }
4636   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4637     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4638   }
4639   ierr = DMSetUp(idm);CHKERRQ(ierr);
4640   /* Get face cones from subsets of cell vertices */
4641   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4642   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4643   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4644   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4645   for (f = firstFace; f < firstFace+numFaces; ++f) {
4646     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4647   }
4648   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4649   for (c = 0, face = firstFace; c < numCells; ++c) {
4650     const PetscInt *cellFaces;
4651     PetscInt        numCellFaces, faceSize, cf;
4652 
4653     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4654     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4655     for (cf = 0; cf < numCellFaces; ++cf) {
4656       PetscBool found = PETSC_FALSE;
4657 
4658       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4659       for (f = firstFace; f < face; ++f) {
4660         const PetscInt *cone = PETSC_NULL;
4661 
4662         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4663         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4664             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4665             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4666             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4667             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4668             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4669           found = PETSC_TRUE;
4670           break;
4671         }
4672       }
4673       if (!found) {
4674         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4675         /* Save the vertices for orientation calculation */
4676         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4677         ++face;
4678       }
4679       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4680     }
4681   }
4682   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4683   /* Get edge cones from subsets of face vertices */
4684   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4685     const PetscInt *cellFaces;
4686     PetscInt        numCellFaces, faceSize, cf;
4687 
4688     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4689     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4690     for (cf = 0; cf < numCellFaces; ++cf) {
4691       PetscBool found = PETSC_FALSE;
4692 
4693       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4694       for (e = firstEdge; e < edge; ++e) {
4695         const PetscInt *cone = PETSC_NULL;
4696 
4697         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4698         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4699             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4700           found = PETSC_TRUE;
4701           break;
4702         }
4703       }
4704       if (!found) {
4705         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4706         ++edge;
4707       }
4708       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4709     }
4710   }
4711   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4712   ierr = PetscFree(off);CHKERRQ(ierr);
4713   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4714   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4715   mesh = (DM_Plex*) (idm)->data;
4716   /* Orient edges */
4717   for (f = firstFace; f < firstFace+numFaces; ++f) {
4718     const PetscInt *cone, *cellFaces;
4719     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4720 
4721     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4722     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4723     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4724     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4725     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4726     for (cf = 0; cf < numCellFaces; ++cf) {
4727       const PetscInt *econe;
4728       PetscInt        esize;
4729 
4730       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4731       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4732       if (esize != 2) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4733       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4734         /* Correctly oriented */
4735         mesh->coneOrientations[coff+cf] = 0;
4736       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4737         /* Start at index 1, and reverse orientation */
4738         mesh->coneOrientations[coff+cf] = -(1+1);
4739       }
4740     }
4741   }
4742   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4743   /* Orient faces */
4744   for (c = 0; c < numCells; ++c) {
4745     const PetscInt *cone, *cellFaces;
4746     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4747 
4748     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4749     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4750     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4751     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4752     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4753     for (cf = 0; cf < numCellFaces; ++cf) {
4754       PetscInt *origClosure = PETSC_NULL, *closure;
4755       PetscInt closureSize, i;
4756 
4757       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4758       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4759       for (i = 4; i < 7; ++i) {
4760         if ((origClosure[i*2] < vStart) || (origClosure[i*2] >= vEnd)) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure point %D should be a vertex in [%D, %D)", origClosure[i*2], vStart, vEnd);
4761       }
4762       closure = &origClosure[4*2];
4763       /* Remember that this is the orientation for edges, not vertices */
4764       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4765         /* Correctly oriented */
4766         mesh->coneOrientations[coff+cf] = 0;
4767       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4768         /* Shifted by 1 */
4769         mesh->coneOrientations[coff+cf] = 1;
4770       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4771         /* Shifted by 2 */
4772         mesh->coneOrientations[coff+cf] = 2;
4773       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4774         /* Start at edge 1, and reverse orientation */
4775         mesh->coneOrientations[coff+cf] = -(1+1);
4776       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4777         /* Start at index 0, and reverse orientation */
4778         mesh->coneOrientations[coff+cf] = -(0+1);
4779       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4780         /* Start at index 2, and reverse orientation */
4781         mesh->coneOrientations[coff+cf] = -(2+1);
4782       } else SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Face %D did not match local face %D in cell %D for any orientation", cone[cf], cf, c);
4783       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4784     }
4785   }
4786   {
4787     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4788     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4789     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4790   }
4791   *dmInt = idm;
4792   PetscFunctionReturn(0);
4793 }
4794 
4795 #undef __FUNCT__
4796 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4797 /*
4798   This takes as input the common mesh generator output, a list of the vertices for each cell
4799 */
4800 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4801 {
4802   PetscInt      *cone, c, p;
4803   PetscErrorCode ierr;
4804 
4805   PetscFunctionBegin;
4806   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4807   for (c = 0; c < numCells; ++c) {
4808     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4809   }
4810   ierr = DMSetUp(dm);CHKERRQ(ierr);
4811   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4812   for (c = 0; c < numCells; ++c) {
4813     for (p = 0; p < numCorners; ++p) {
4814       cone[p] = cells[c*numCorners+p]+numCells;
4815     }
4816     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4817   }
4818   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4819   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4820   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4821   PetscFunctionReturn(0);
4822 }
4823 
4824 #undef __FUNCT__
4825 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4826 /*
4827   This takes as input the coordinates for each vertex
4828 */
4829 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4830 {
4831   PetscSection   coordSection;
4832   Vec            coordinates;
4833   PetscScalar   *coords;
4834   PetscInt       coordSize, v, d;
4835   PetscErrorCode ierr;
4836 
4837   PetscFunctionBegin;
4838   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4839   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4840   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4841   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4842   for (v = numCells; v < numCells+numVertices; ++v) {
4843     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4844     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4845   }
4846   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4847   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4848   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4849   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4850   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4851   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4852   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4853   for (v = 0; v < numVertices; ++v) {
4854     for (d = 0; d < spaceDim; ++d) {
4855       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4856     }
4857   }
4858   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4859   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4860   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4861   PetscFunctionReturn(0);
4862 }
4863 
4864 #undef __FUNCT__
4865 #define __FUNCT__ "DMPlexCreateFromCellList"
4866 /*
4867   This takes as input the common mesh generator output, a list of the vertices for each cell
4868 */
4869 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4870 {
4871   PetscErrorCode ierr;
4872 
4873   PetscFunctionBegin;
4874   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4875   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4876   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4877   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4878   if (interpolate) {
4879     DM idm;
4880 
4881     switch (dim) {
4882     case 2:
4883       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4884     case 3:
4885       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4886     default:
4887       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4888     }
4889     ierr = DMDestroy(dm);CHKERRQ(ierr);
4890     *dm  = idm;
4891   }
4892   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4893   PetscFunctionReturn(0);
4894 }
4895 
4896 #if defined(PETSC_HAVE_TRIANGLE)
4897 #include <triangle.h>
4898 
4899 #undef __FUNCT__
4900 #define __FUNCT__ "InitInput_Triangle"
4901 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4902 {
4903   PetscFunctionBegin;
4904   inputCtx->numberofpoints             = 0;
4905   inputCtx->numberofpointattributes    = 0;
4906   inputCtx->pointlist                  = PETSC_NULL;
4907   inputCtx->pointattributelist         = PETSC_NULL;
4908   inputCtx->pointmarkerlist            = PETSC_NULL;
4909   inputCtx->numberofsegments           = 0;
4910   inputCtx->segmentlist                = PETSC_NULL;
4911   inputCtx->segmentmarkerlist          = PETSC_NULL;
4912   inputCtx->numberoftriangleattributes = 0;
4913   inputCtx->trianglelist               = PETSC_NULL;
4914   inputCtx->numberofholes              = 0;
4915   inputCtx->holelist                   = PETSC_NULL;
4916   inputCtx->numberofregions            = 0;
4917   inputCtx->regionlist                 = PETSC_NULL;
4918   PetscFunctionReturn(0);
4919 }
4920 
4921 #undef __FUNCT__
4922 #define __FUNCT__ "InitOutput_Triangle"
4923 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4924 {
4925   PetscFunctionBegin;
4926   outputCtx->numberofpoints        = 0;
4927   outputCtx->pointlist             = PETSC_NULL;
4928   outputCtx->pointattributelist    = PETSC_NULL;
4929   outputCtx->pointmarkerlist       = PETSC_NULL;
4930   outputCtx->numberoftriangles     = 0;
4931   outputCtx->trianglelist          = PETSC_NULL;
4932   outputCtx->triangleattributelist = PETSC_NULL;
4933   outputCtx->neighborlist          = PETSC_NULL;
4934   outputCtx->segmentlist           = PETSC_NULL;
4935   outputCtx->segmentmarkerlist     = PETSC_NULL;
4936   outputCtx->numberofedges         = 0;
4937   outputCtx->edgelist              = PETSC_NULL;
4938   outputCtx->edgemarkerlist        = PETSC_NULL;
4939   PetscFunctionReturn(0);
4940 }
4941 
4942 #undef __FUNCT__
4943 #define __FUNCT__ "FiniOutput_Triangle"
4944 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4945 {
4946   PetscFunctionBegin;
4947   free(outputCtx->pointmarkerlist);
4948   free(outputCtx->edgelist);
4949   free(outputCtx->edgemarkerlist);
4950   free(outputCtx->trianglelist);
4951   free(outputCtx->neighborlist);
4952   PetscFunctionReturn(0);
4953 }
4954 
4955 #undef __FUNCT__
4956 #define __FUNCT__ "DMPlexGenerate_Triangle"
4957 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4958 {
4959   MPI_Comm             comm             = ((PetscObject) boundary)->comm;
4960   PetscInt             dim              = 2;
4961   const PetscBool      createConvexHull = PETSC_FALSE;
4962   const PetscBool      constrained      = PETSC_FALSE;
4963   struct triangulateio in;
4964   struct triangulateio out;
4965   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4966   PetscMPIInt          rank;
4967   PetscErrorCode       ierr;
4968 
4969   PetscFunctionBegin;
4970   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4971   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4972   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4973   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4974 
4975   in.numberofpoints = vEnd - vStart;
4976   if (in.numberofpoints > 0) {
4977     PetscSection coordSection;
4978     Vec          coordinates;
4979     PetscScalar *array;
4980 
4981     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4982     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4983     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4984     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4985     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4986     for (v = vStart; v < vEnd; ++v) {
4987       const PetscInt idx = v - vStart;
4988       PetscInt       off, d;
4989 
4990       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4991       for (d = 0; d < dim; ++d) {
4992         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4993       }
4994       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4995     }
4996     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4997   }
4998   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4999   in.numberofsegments = eEnd - eStart;
5000   if (in.numberofsegments > 0) {
5001     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
5002     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
5003     for (e = eStart; e < eEnd; ++e) {
5004       const PetscInt  idx = e - eStart;
5005       const PetscInt *cone;
5006 
5007       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
5008 
5009       in.segmentlist[idx*2+0] = cone[0] - vStart;
5010       in.segmentlist[idx*2+1] = cone[1] - vStart;
5011 
5012       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5013     }
5014   }
5015 #if 0 /* Do not currently support holes */
5016   PetscReal *holeCoords;
5017   PetscInt   h, d;
5018 
5019   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5020   if (in.numberofholes > 0) {
5021     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5022     for (h = 0; h < in.numberofholes; ++h) {
5023       for (d = 0; d < dim; ++d) {
5024         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5025       }
5026     }
5027   }
5028 #endif
5029   if (!rank) {
5030     char args[32];
5031 
5032     /* Take away 'Q' for verbose output */
5033     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5034     if (createConvexHull) {
5035       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5036     }
5037     if (constrained) {
5038       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5039     }
5040     triangulate(args, &in, &out, PETSC_NULL);
5041   }
5042   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5043   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5044   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5045   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5046   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5047 
5048   {
5049     const PetscInt numCorners  = 3;
5050     const PetscInt numCells    = out.numberoftriangles;
5051     const PetscInt numVertices = out.numberofpoints;
5052     const int     *cells      = out.trianglelist;
5053     const double  *meshCoords = out.pointlist;
5054 
5055     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5056     /* Set labels */
5057     for (v = 0; v < numVertices; ++v) {
5058       if (out.pointmarkerlist[v]) {
5059         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5060       }
5061     }
5062     if (interpolate) {
5063       for (e = 0; e < out.numberofedges; e++) {
5064         if (out.edgemarkerlist[e]) {
5065           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5066           const PetscInt *edges;
5067           PetscInt        numEdges;
5068 
5069           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5070           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5071           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5072           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5073         }
5074       }
5075     }
5076     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5077   }
5078 #if 0 /* Do not currently support holes */
5079   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5080 #endif
5081   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5082   PetscFunctionReturn(0);
5083 }
5084 
5085 #undef __FUNCT__
5086 #define __FUNCT__ "DMPlexRefine_Triangle"
5087 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5088 {
5089   MPI_Comm             comm = ((PetscObject) dm)->comm;
5090   PetscInt             dim  = 2;
5091   struct triangulateio in;
5092   struct triangulateio out;
5093   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5094   PetscMPIInt          rank;
5095   PetscErrorCode       ierr;
5096 
5097   PetscFunctionBegin;
5098   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5099   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5100   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5101   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5102   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5103   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5104 
5105   in.numberofpoints = vEnd - vStart;
5106   if (in.numberofpoints > 0) {
5107     PetscSection coordSection;
5108     Vec          coordinates;
5109     PetscScalar *array;
5110 
5111     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5112     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5113     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5114     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5115     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5116     for (v = vStart; v < vEnd; ++v) {
5117       const PetscInt idx = v - vStart;
5118       PetscInt       off, d;
5119 
5120       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5121       for (d = 0; d < dim; ++d) {
5122         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5123       }
5124       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5125     }
5126     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5127   }
5128   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5129 
5130   in.numberofcorners   = 3;
5131   in.numberoftriangles = cEnd - cStart;
5132 
5133   in.trianglearealist  = (double*) maxVolumes;
5134   if (in.numberoftriangles > 0) {
5135     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5136     for (c = cStart; c < cEnd; ++c) {
5137       const PetscInt idx      = c - cStart;
5138       PetscInt      *closure = PETSC_NULL;
5139       PetscInt       closureSize;
5140 
5141       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5142       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5143       for (v = 0; v < 3; ++v) {
5144         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5145       }
5146       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5147     }
5148   }
5149   /* TODO: Segment markers are missing on input */
5150 #if 0 /* Do not currently support holes */
5151   PetscReal *holeCoords;
5152   PetscInt   h, d;
5153 
5154   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5155   if (in.numberofholes > 0) {
5156     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5157     for (h = 0; h < in.numberofholes; ++h) {
5158       for (d = 0; d < dim; ++d) {
5159         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5160       }
5161     }
5162   }
5163 #endif
5164   if (!rank) {
5165     char args[32];
5166 
5167     /* Take away 'Q' for verbose output */
5168     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5169     triangulate(args, &in, &out, PETSC_NULL);
5170   }
5171   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5172   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5173   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5174   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5175   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5176 
5177   {
5178     const PetscInt numCorners  = 3;
5179     const PetscInt numCells    = out.numberoftriangles;
5180     const PetscInt numVertices = out.numberofpoints;
5181     const int     *cells      = out.trianglelist;
5182     const double  *meshCoords = out.pointlist;
5183     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5184 
5185     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5186     /* Set labels */
5187     for (v = 0; v < numVertices; ++v) {
5188       if (out.pointmarkerlist[v]) {
5189         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5190       }
5191     }
5192     if (interpolate) {
5193       PetscInt e;
5194 
5195       for (e = 0; e < out.numberofedges; e++) {
5196         if (out.edgemarkerlist[e]) {
5197           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5198           const PetscInt *edges;
5199           PetscInt        numEdges;
5200 
5201           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5202           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5203           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5204           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5205         }
5206       }
5207     }
5208     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5209   }
5210 #if 0 /* Do not currently support holes */
5211   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5212 #endif
5213   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5214   PetscFunctionReturn(0);
5215 }
5216 #endif
5217 
5218 #if defined(PETSC_HAVE_TETGEN)
5219 #include <tetgen.h>
5220 #undef __FUNCT__
5221 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5222 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5223 {
5224   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5225   const PetscInt dim  = 3;
5226   ::tetgenio     in;
5227   ::tetgenio     out;
5228   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5229   PetscMPIInt    rank;
5230   PetscErrorCode ierr;
5231 
5232   PetscFunctionBegin;
5233   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5234   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5235   in.numberofpoints = vEnd - vStart;
5236   if (in.numberofpoints > 0) {
5237     PetscSection coordSection;
5238     Vec          coordinates;
5239     PetscScalar *array;
5240 
5241     in.pointlist       = new double[in.numberofpoints*dim];
5242     in.pointmarkerlist = new int[in.numberofpoints];
5243 
5244     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5245     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5246     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5247     for (v = vStart; v < vEnd; ++v) {
5248       const PetscInt idx = v - vStart;
5249       PetscInt       off, d;
5250 
5251       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5252       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5253       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5254     }
5255     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5256   }
5257   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5258 
5259   in.numberoffacets = fEnd - fStart;
5260   if (in.numberoffacets > 0) {
5261     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5262     in.facetmarkerlist = new int[in.numberoffacets];
5263     for (f = fStart; f < fEnd; ++f) {
5264       const PetscInt idx     = f - fStart;
5265       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5266 
5267       in.facetlist[idx].numberofpolygons = 1;
5268       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5269       in.facetlist[idx].numberofholes    = 0;
5270       in.facetlist[idx].holelist         = NULL;
5271 
5272       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5273       for (p = 0; p < numPoints*2; p += 2) {
5274         const PetscInt point = points[p];
5275         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5276       }
5277 
5278       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5279       poly->numberofvertices = numVertices;
5280       poly->vertexlist       = new int[poly->numberofvertices];
5281       for (v = 0; v < numVertices; ++v) {
5282         const PetscInt vIdx = points[v] - vStart;
5283         poly->vertexlist[v] = vIdx;
5284       }
5285       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5286       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5287     }
5288   }
5289   if (!rank) {
5290     char args[32];
5291 
5292     /* Take away 'Q' for verbose output */
5293     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5294     ::tetrahedralize(args, &in, &out);
5295   }
5296   {
5297     const PetscInt numCorners  = 4;
5298     const PetscInt numCells    = out.numberoftetrahedra;
5299     const PetscInt numVertices = out.numberofpoints;
5300     const int     *cells      = out.tetrahedronlist;
5301     const double  *meshCoords = out.pointlist;
5302 
5303     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5304     /* Set labels */
5305     for (v = 0; v < numVertices; ++v) {
5306       if (out.pointmarkerlist[v]) {
5307         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5308       }
5309     }
5310     if (interpolate) {
5311       PetscInt e;
5312 
5313       for (e = 0; e < out.numberofedges; e++) {
5314         if (out.edgemarkerlist[e]) {
5315           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5316           const PetscInt *edges;
5317           PetscInt        numEdges;
5318 
5319           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5320           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5321           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5322           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5323         }
5324       }
5325       for (f = 0; f < out.numberoftrifaces; f++) {
5326         if (out.trifacemarkerlist[f]) {
5327           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5328           const PetscInt *faces;
5329           PetscInt        numFaces;
5330 
5331           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5332           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5333           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5334           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5335         }
5336       }
5337     }
5338     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5339   }
5340   PetscFunctionReturn(0);
5341 }
5342 
5343 #undef __FUNCT__
5344 #define __FUNCT__ "DMPlexRefine_Tetgen"
5345 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5346 {
5347   MPI_Comm       comm = ((PetscObject) dm)->comm;
5348   const PetscInt dim  = 3;
5349   ::tetgenio     in;
5350   ::tetgenio     out;
5351   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5352   PetscMPIInt    rank;
5353   PetscErrorCode ierr;
5354 
5355   PetscFunctionBegin;
5356   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5357   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5358   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5359   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5360 
5361   in.numberofpoints = vEnd - vStart;
5362   if (in.numberofpoints > 0) {
5363     PetscSection coordSection;
5364     Vec          coordinates;
5365     PetscScalar *array;
5366 
5367     in.pointlist       = new double[in.numberofpoints*dim];
5368     in.pointmarkerlist = new int[in.numberofpoints];
5369 
5370     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5371     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5372     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5373     for (v = vStart; v < vEnd; ++v) {
5374       const PetscInt idx = v - vStart;
5375       PetscInt       off, d;
5376 
5377       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5378       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5379       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5380     }
5381     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5382   }
5383   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5384 
5385   in.numberofcorners       = 4;
5386   in.numberoftetrahedra    = cEnd - cStart;
5387   in.tetrahedronvolumelist = (double*) maxVolumes;
5388   if (in.numberoftetrahedra > 0) {
5389     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5390     for (c = cStart; c < cEnd; ++c) {
5391       const PetscInt idx      = c - cStart;
5392       PetscInt      *closure = PETSC_NULL;
5393       PetscInt       closureSize;
5394 
5395       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5396       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5397       for (v = 0; v < 4; ++v) {
5398         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5399       }
5400       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5401     }
5402   }
5403   /* TODO: Put in boundary faces with markers */
5404   if (!rank) {
5405     char args[32];
5406 
5407     /* Take away 'Q' for verbose output */
5408     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5409     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5410     ::tetrahedralize(args, &in, &out);
5411   }
5412   in.tetrahedronvolumelist = NULL;
5413 
5414   {
5415     const PetscInt numCorners  = 4;
5416     const PetscInt numCells    = out.numberoftetrahedra;
5417     const PetscInt numVertices = out.numberofpoints;
5418     const int     *cells      = out.tetrahedronlist;
5419     const double  *meshCoords = out.pointlist;
5420     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5421 
5422     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5423     /* Set labels */
5424     for (v = 0; v < numVertices; ++v) {
5425       if (out.pointmarkerlist[v]) {
5426         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5427       }
5428     }
5429     if (interpolate) {
5430       PetscInt e, f;
5431 
5432       for (e = 0; e < out.numberofedges; e++) {
5433         if (out.edgemarkerlist[e]) {
5434           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5435           const PetscInt *edges;
5436           PetscInt        numEdges;
5437 
5438           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5439           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5440           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5441           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5442         }
5443       }
5444       for (f = 0; f < out.numberoftrifaces; f++) {
5445         if (out.trifacemarkerlist[f]) {
5446           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5447           const PetscInt *faces;
5448           PetscInt        numFaces;
5449 
5450           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5451           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5452           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5453           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5454         }
5455       }
5456     }
5457     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5458   }
5459   PetscFunctionReturn(0);
5460 }
5461 #endif
5462 
5463 #if defined(PETSC_HAVE_CTETGEN)
5464 #include "ctetgen.h"
5465 
5466 #undef __FUNCT__
5467 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5468 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5469 {
5470   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5471   const PetscInt dim  = 3;
5472   PLC           *in, *out;
5473   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5474   PetscMPIInt    rank;
5475   PetscErrorCode ierr;
5476 
5477   PetscFunctionBegin;
5478   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5479   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5480   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5481   ierr = PLCCreate(&in);CHKERRQ(ierr);
5482   ierr = PLCCreate(&out);CHKERRQ(ierr);
5483 
5484   in->numberofpoints = vEnd - vStart;
5485   if (in->numberofpoints > 0) {
5486     PetscSection coordSection;
5487     Vec          coordinates;
5488     PetscScalar *array;
5489 
5490     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5491     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5492     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5493     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5494     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5495     for (v = vStart; v < vEnd; ++v) {
5496       const PetscInt idx = v - vStart;
5497       PetscInt       off, d, m;
5498 
5499       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5500       for (d = 0; d < dim; ++d) {
5501         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5502       }
5503       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5504 
5505       in->pointmarkerlist[idx] = (int) m;
5506     }
5507     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5508   }
5509   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5510 
5511   in->numberoffacets = fEnd - fStart;
5512   if (in->numberoffacets > 0) {
5513     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5514     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5515     for (f = fStart; f < fEnd; ++f) {
5516       const PetscInt idx     = f - fStart;
5517       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5518       polygon       *poly;
5519 
5520       in->facetlist[idx].numberofpolygons = 1;
5521 
5522       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5523 
5524       in->facetlist[idx].numberofholes    = 0;
5525       in->facetlist[idx].holelist         = PETSC_NULL;
5526 
5527       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5528       for (p = 0; p < numPoints*2; p += 2) {
5529         const PetscInt point = points[p];
5530         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5531       }
5532 
5533       poly                   = in->facetlist[idx].polygonlist;
5534       poly->numberofvertices = numVertices;
5535       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5536       for (v = 0; v < numVertices; ++v) {
5537         const PetscInt vIdx = points[v] - vStart;
5538         poly->vertexlist[v] = vIdx;
5539       }
5540       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5541       in->facetmarkerlist[idx] = (int) m;
5542       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5543     }
5544   }
5545   if (!rank) {
5546     TetGenOpts t;
5547 
5548     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5549     t.in        = boundary; /* Should go away */
5550     t.plc       = 1;
5551     t.quality   = 1;
5552     t.edgesout  = 1;
5553     t.zeroindex = 1;
5554     t.quiet     = 1;
5555     t.verbose   = verbose;
5556     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5557     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5558   }
5559   {
5560     const PetscInt numCorners  = 4;
5561     const PetscInt numCells    = out->numberoftetrahedra;
5562     const PetscInt numVertices = out->numberofpoints;
5563     const int     *cells      = out->tetrahedronlist;
5564     const double  *meshCoords = out->pointlist;
5565 
5566     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5567     /* Set labels */
5568     for (v = 0; v < numVertices; ++v) {
5569       if (out->pointmarkerlist[v]) {
5570         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5571       }
5572     }
5573     if (interpolate) {
5574       PetscInt e;
5575 
5576       for (e = 0; e < out->numberofedges; e++) {
5577         if (out->edgemarkerlist[e]) {
5578           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5579           const PetscInt *edges;
5580           PetscInt        numEdges;
5581 
5582           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5583           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5584           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5585           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5586         }
5587       }
5588       for (f = 0; f < out->numberoftrifaces; f++) {
5589         if (out->trifacemarkerlist[f]) {
5590           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5591           const PetscInt *faces;
5592           PetscInt        numFaces;
5593 
5594           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5595           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5596           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5597           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5598         }
5599       }
5600     }
5601     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5602   }
5603 
5604   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5605   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5606   PetscFunctionReturn(0);
5607 }
5608 
5609 #undef __FUNCT__
5610 #define __FUNCT__ "DMPlexRefine_CTetgen"
5611 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5612 {
5613   MPI_Comm       comm = ((PetscObject) dm)->comm;
5614   const PetscInt dim  = 3;
5615   PLC           *in, *out;
5616   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5617   PetscMPIInt    rank;
5618   PetscErrorCode ierr;
5619 
5620   PetscFunctionBegin;
5621   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5622   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5623   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5624   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5625   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5626   ierr = PLCCreate(&in);CHKERRQ(ierr);
5627   ierr = PLCCreate(&out);CHKERRQ(ierr);
5628 
5629   in->numberofpoints = vEnd - vStart;
5630   if (in->numberofpoints > 0) {
5631     PetscSection coordSection;
5632     Vec          coordinates;
5633     PetscScalar *array;
5634 
5635     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5636     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5637     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5638     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5639     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5640     for (v = vStart; v < vEnd; ++v) {
5641       const PetscInt idx = v - vStart;
5642       PetscInt       off, d, m;
5643 
5644       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5645       for (d = 0; d < dim; ++d) {
5646         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5647       }
5648       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5649 
5650       in->pointmarkerlist[idx] = (int) m;
5651     }
5652     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5653   }
5654   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5655 
5656   in->numberofcorners       = 4;
5657   in->numberoftetrahedra    = cEnd - cStart;
5658   in->tetrahedronvolumelist = maxVolumes;
5659   if (in->numberoftetrahedra > 0) {
5660     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5661     for (c = cStart; c < cEnd; ++c) {
5662       const PetscInt idx      = c - cStart;
5663       PetscInt      *closure = PETSC_NULL;
5664       PetscInt       closureSize;
5665 
5666       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5667       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5668       for (v = 0; v < 4; ++v) {
5669         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5670       }
5671       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5672     }
5673   }
5674   if (!rank) {
5675     TetGenOpts t;
5676 
5677     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5678 
5679     t.in        = dm; /* Should go away */
5680     t.refine    = 1;
5681     t.varvolume = 1;
5682     t.quality   = 1;
5683     t.edgesout  = 1;
5684     t.zeroindex = 1;
5685     t.quiet     = 1;
5686     t.verbose   = verbose; /* Change this */
5687 
5688     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5689     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5690   }
5691   {
5692     const PetscInt numCorners  = 4;
5693     const PetscInt numCells    = out->numberoftetrahedra;
5694     const PetscInt numVertices = out->numberofpoints;
5695     const int     *cells       = out->tetrahedronlist;
5696     const double  *meshCoords  = out->pointlist;
5697     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5698 
5699     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5700     /* Set labels */
5701     for (v = 0; v < numVertices; ++v) {
5702       if (out->pointmarkerlist[v]) {
5703         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5704       }
5705     }
5706     if (interpolate) {
5707       PetscInt e, f;
5708 
5709       for (e = 0; e < out->numberofedges; e++) {
5710         if (out->edgemarkerlist[e]) {
5711           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5712           const PetscInt *edges;
5713           PetscInt        numEdges;
5714 
5715           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5716           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5717           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5718           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5719         }
5720       }
5721       for (f = 0; f < out->numberoftrifaces; f++) {
5722         if (out->trifacemarkerlist[f]) {
5723           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5724           const PetscInt *faces;
5725           PetscInt        numFaces;
5726 
5727           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5728           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5729           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5730           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5731         }
5732       }
5733     }
5734     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5735   }
5736   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5737   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5738   PetscFunctionReturn(0);
5739 }
5740 #endif
5741 
5742 #undef __FUNCT__
5743 #define __FUNCT__ "DMPlexGenerate"
5744 /*@C
5745   DMPlexGenerate - Generates a mesh.
5746 
5747   Not Collective
5748 
5749   Input Parameters:
5750 + boundary - The DMPlex boundary object
5751 . name - The mesh generation package name
5752 - interpolate - Flag to create intermediate mesh elements
5753 
5754   Output Parameter:
5755 . mesh - The DMPlex object
5756 
5757   Level: intermediate
5758 
5759 .keywords: mesh, elements
5760 .seealso: DMPlexCreate(), DMRefine()
5761 @*/
5762 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5763 {
5764   PetscInt       dim;
5765   char           genname[1024];
5766   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5767   PetscErrorCode ierr;
5768 
5769   PetscFunctionBegin;
5770   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5771   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5772   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5773   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5774   if (flg) name = genname;
5775   if (name) {
5776     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5777     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5778     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5779   }
5780   switch (dim) {
5781   case 1:
5782     if (!name || isTriangle) {
5783 #if defined(PETSC_HAVE_TRIANGLE)
5784       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5785 #else
5786       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5787 #endif
5788     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5789     break;
5790   case 2:
5791     if (!name || isCTetgen) {
5792 #if defined(PETSC_HAVE_CTETGEN)
5793       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5794 #else
5795       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5796 #endif
5797     } else if (isTetgen) {
5798 #if defined(PETSC_HAVE_TETGEN)
5799       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5800 #else
5801       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5802 #endif
5803     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5804     break;
5805   default:
5806     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5807   }
5808   PetscFunctionReturn(0);
5809 }
5810 
5811 typedef PetscInt CellRefiner;
5812 
5813 #undef __FUNCT__
5814 #define __FUNCT__ "GetDepthStart_Private"
5815 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5816 {
5817   PetscFunctionBegin;
5818   if (cStart) *cStart = 0;
5819   if (vStart) *vStart = depthSize[depth];
5820   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5821   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5822   PetscFunctionReturn(0);
5823 }
5824 
5825 #undef __FUNCT__
5826 #define __FUNCT__ "GetDepthEnd_Private"
5827 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5828 {
5829   PetscFunctionBegin;
5830   if (cEnd) *cEnd = depthSize[depth];
5831   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5832   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5833   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5834   PetscFunctionReturn(0);
5835 }
5836 
5837 #undef __FUNCT__
5838 #define __FUNCT__ "CellRefinerGetSizes"
5839 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5840 {
5841   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5842   PetscErrorCode ierr;
5843 
5844   PetscFunctionBegin;
5845   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5846   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5847   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5848   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5849   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5850   switch (refiner) {
5851   case 1:
5852     /* Simplicial 2D */
5853     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5854     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5855     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5856     break;
5857   case 3:
5858     /* Hybrid 2D */
5859     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5860     cMax = PetscMin(cEnd, cMax);
5861     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5862     fMax         = PetscMin(fEnd, fMax);
5863     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5864     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 */
5865     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5866     break;
5867   case 2:
5868     /* Hex 2D */
5869     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5870     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5871     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5872     break;
5873   default:
5874     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5875   }
5876   PetscFunctionReturn(0);
5877 }
5878 
5879 #undef __FUNCT__
5880 #define __FUNCT__ "CellRefinerSetConeSizes"
5881 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5882 {
5883   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5884   PetscErrorCode ierr;
5885 
5886   PetscFunctionBegin;
5887   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5888   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5889   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5890   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5891   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5892   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5893   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5894   switch (refiner) {
5895   case 1:
5896     /* Simplicial 2D */
5897     /* All cells have 3 faces */
5898     for (c = cStart; c < cEnd; ++c) {
5899       for (r = 0; r < 4; ++r) {
5900         const PetscInt newp = (c - cStart)*4 + r;
5901 
5902         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5903       }
5904     }
5905     /* Split faces have 2 vertices and the same cells as the parent */
5906     for (f = fStart; f < fEnd; ++f) {
5907       for (r = 0; r < 2; ++r) {
5908         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5909         PetscInt       size;
5910 
5911         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5912         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5913         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5914       }
5915     }
5916     /* Interior faces have 2 vertices and 2 cells */
5917     for (c = cStart; c < cEnd; ++c) {
5918       for (r = 0; r < 3; ++r) {
5919         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5920 
5921         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5922         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5923       }
5924     }
5925     /* Old vertices have identical supports */
5926     for (v = vStart; v < vEnd; ++v) {
5927       const PetscInt newp = vStartNew + (v - vStart);
5928       PetscInt       size;
5929 
5930       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5931       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5932     }
5933     /* Face vertices have 2 + cells*2 supports */
5934     for (f = fStart; f < fEnd; ++f) {
5935       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5936       PetscInt       size;
5937 
5938       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5939       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5940     }
5941     break;
5942   case 2:
5943     /* Hex 2D */
5944     /* All cells have 4 faces */
5945     for (c = cStart; c < cEnd; ++c) {
5946       for (r = 0; r < 4; ++r) {
5947         const PetscInt newp = (c - cStart)*4 + r;
5948 
5949         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5950       }
5951     }
5952     /* Split faces have 2 vertices and the same cells as the parent */
5953     for (f = fStart; f < fEnd; ++f) {
5954       for (r = 0; r < 2; ++r) {
5955         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5956         PetscInt       size;
5957 
5958         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5959         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5960         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5961       }
5962     }
5963     /* Interior faces have 2 vertices and 2 cells */
5964     for (c = cStart; c < cEnd; ++c) {
5965       for (r = 0; r < 4; ++r) {
5966         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5967 
5968         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5969         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5970       }
5971     }
5972     /* Old vertices have identical supports */
5973     for (v = vStart; v < vEnd; ++v) {
5974       const PetscInt newp = vStartNew + (v - vStart);
5975       PetscInt       size;
5976 
5977       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5978       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5979     }
5980     /* Face vertices have 2 + cells supports */
5981     for (f = fStart; f < fEnd; ++f) {
5982       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5983       PetscInt       size;
5984 
5985       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5986       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5987     }
5988     /* Cell vertices have 4 supports */
5989     for (c = cStart; c < cEnd; ++c) {
5990       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5991 
5992       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5993     }
5994     break;
5995   case 3:
5996     /* Hybrid 2D */
5997     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5998     cMax = PetscMin(cEnd, cMax);
5999     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6000     fMax = PetscMin(fEnd, fMax);
6001     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6002     /* Interior cells have 3 faces */
6003     for (c = cStart; c < cMax; ++c) {
6004       for (r = 0; r < 4; ++r) {
6005         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
6006 
6007         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
6008       }
6009     }
6010     /* Hybrid cells have 4 faces */
6011     for (c = cMax; c < cEnd; ++c) {
6012       for (r = 0; r < 2; ++r) {
6013         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
6014 
6015         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6016       }
6017     }
6018     /* Interior split faces have 2 vertices and the same cells as the parent */
6019     for (f = fStart; f < fMax; ++f) {
6020       for (r = 0; r < 2; ++r) {
6021         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6022         PetscInt       size;
6023 
6024         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6025         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6026         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6027       }
6028     }
6029     /* Interior cell faces have 2 vertices and 2 cells */
6030     for (c = cStart; c < cMax; ++c) {
6031       for (r = 0; r < 3; ++r) {
6032         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6033 
6034         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6035         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6036       }
6037     }
6038     /* Hybrid faces have 2 vertices and the same cells */
6039     for (f = fMax; f < fEnd; ++f) {
6040       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6041       PetscInt       size;
6042 
6043       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6044       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6045       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6046     }
6047     /* Hybrid cell faces have 2 vertices and 2 cells */
6048     for (c = cMax; c < cEnd; ++c) {
6049       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6050 
6051       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6052       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6053     }
6054     /* Old vertices have identical supports */
6055     for (v = vStart; v < vEnd; ++v) {
6056       const PetscInt newp = vStartNew + (v - vStart);
6057       PetscInt       size;
6058 
6059       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6060       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6061     }
6062     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6063     for (f = fStart; f < fMax; ++f) {
6064       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6065       const PetscInt *support;
6066       PetscInt       size, newSize = 2, s;
6067 
6068       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6069       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6070       for (s = 0; s < size; ++s) {
6071         if (support[s] >= cMax) newSize += 1;
6072         else newSize += 2;
6073       }
6074       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6075     }
6076     break;
6077   default:
6078     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6079   }
6080   PetscFunctionReturn(0);
6081 }
6082 
6083 #undef __FUNCT__
6084 #define __FUNCT__ "CellRefinerSetCones"
6085 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6086 {
6087   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;
6088   PetscInt       maxSupportSize, *supportRef;
6089   PetscErrorCode ierr;
6090 
6091   PetscFunctionBegin;
6092   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6093   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6094   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6095   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6096   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6097   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6098   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6099   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6100   switch (refiner) {
6101   case 1:
6102     /* Simplicial 2D */
6103     /*
6104      2
6105      |\
6106      | \
6107      |  \
6108      |   \
6109      | C  \
6110      |     \
6111      |      \
6112      2---1---1
6113      |\  D  / \
6114      | 2   0   \
6115      |A \ /  B  \
6116      0---0-------1
6117      */
6118     /* All cells have 3 faces */
6119     for (c = cStart; c < cEnd; ++c) {
6120       const PetscInt  newp = cStartNew + (c - cStart)*4;
6121       const PetscInt *cone, *ornt;
6122       PetscInt        coneNew[3], orntNew[3];
6123 
6124       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6125       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6126       /* A triangle */
6127       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6128       orntNew[0] = ornt[0];
6129       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6130       orntNew[1] = -2;
6131       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6132       orntNew[2] = ornt[2];
6133       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6134       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6135 #if 1
6136       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6137       for (p = 0; p < 3; ++p) {
6138         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6139       }
6140 #endif
6141       /* B triangle */
6142       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6143       orntNew[0] = ornt[0];
6144       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6145       orntNew[1] = ornt[1];
6146       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6147       orntNew[2] = -2;
6148       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6149       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6150 #if 1
6151       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6152       for (p = 0; p < 3; ++p) {
6153         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6154       }
6155 #endif
6156       /* C triangle */
6157       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6158       orntNew[0] = -2;
6159       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6160       orntNew[1] = ornt[1];
6161       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6162       orntNew[2] = ornt[2];
6163       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6164       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6165 #if 1
6166       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6167       for (p = 0; p < 3; ++p) {
6168         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6169       }
6170 #endif
6171       /* D triangle */
6172       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6173       orntNew[0] = 0;
6174       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6175       orntNew[1] = 0;
6176       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6177       orntNew[2] = 0;
6178       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6179       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6180 #if 1
6181       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6182       for (p = 0; p < 3; ++p) {
6183         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6184       }
6185 #endif
6186     }
6187     /* Split faces have 2 vertices and the same cells as the parent */
6188     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6189     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6190     for (f = fStart; f < fEnd; ++f) {
6191       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6192 
6193       for (r = 0; r < 2; ++r) {
6194         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6195         const PetscInt *cone, *support;
6196         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6197 
6198         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6199         coneNew[0]       = vStartNew + (cone[0] - vStart);
6200         coneNew[1]       = vStartNew + (cone[1] - vStart);
6201         coneNew[(r+1)%2] = newv;
6202         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6203 #if 1
6204         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6205         for (p = 0; p < 2; ++p) {
6206           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6207         }
6208 #endif
6209         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6210         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6211         for (s = 0; s < supportSize; ++s) {
6212           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6213           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6214           for (c = 0; c < coneSize; ++c) {
6215             if (cone[c] == f) break;
6216           }
6217           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6218         }
6219         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6220 #if 1
6221         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6222         for (p = 0; p < supportSize; ++p) {
6223           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6224         }
6225 #endif
6226       }
6227     }
6228     /* Interior faces have 2 vertices and 2 cells */
6229     for (c = cStart; c < cEnd; ++c) {
6230       const PetscInt *cone;
6231 
6232       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6233       for (r = 0; r < 3; ++r) {
6234         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6235         PetscInt       coneNew[2];
6236         PetscInt       supportNew[2];
6237 
6238         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6239         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6240         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6241 #if 1
6242         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6243         for (p = 0; p < 2; ++p) {
6244           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6245         }
6246 #endif
6247         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6248         supportNew[1] = (c - cStart)*4 + 3;
6249         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6250 #if 1
6251         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6252         for (p = 0; p < 2; ++p) {
6253           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6254         }
6255 #endif
6256       }
6257     }
6258     /* Old vertices have identical supports */
6259     for (v = vStart; v < vEnd; ++v) {
6260       const PetscInt  newp = vStartNew + (v - vStart);
6261       const PetscInt *support, *cone;
6262       PetscInt        size, s;
6263 
6264       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6265       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6266       for (s = 0; s < size; ++s) {
6267         PetscInt r = 0;
6268 
6269         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6270         if (cone[1] == v) r = 1;
6271         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6272       }
6273       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6274 #if 1
6275       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6276       for (p = 0; p < size; ++p) {
6277         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6278       }
6279 #endif
6280     }
6281     /* Face vertices have 2 + cells*2 supports */
6282     for (f = fStart; f < fEnd; ++f) {
6283       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6284       const PetscInt *cone, *support;
6285       PetscInt        size, s;
6286 
6287       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6288       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6289       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6290       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6291       for (s = 0; s < size; ++s) {
6292         PetscInt r = 0;
6293 
6294         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6295         if      (cone[1] == f) r = 1;
6296         else if (cone[2] == f) r = 2;
6297         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6298         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6299       }
6300       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6301 #if 1
6302       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6303       for (p = 0; p < 2+size*2; ++p) {
6304         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6305       }
6306 #endif
6307     }
6308     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6309     break;
6310   case 2:
6311     /* Hex 2D */
6312     /*
6313      3---------2---------2
6314      |         |         |
6315      |    D    2    C    |
6316      |         |         |
6317      3----3----0----1----1
6318      |         |         |
6319      |    A    0    B    |
6320      |         |         |
6321      0---------0---------1
6322      */
6323     /* All cells have 4 faces */
6324     for (c = cStart; c < cEnd; ++c) {
6325       const PetscInt  newp = (c - cStart)*4;
6326       const PetscInt *cone, *ornt;
6327       PetscInt        coneNew[4], orntNew[4];
6328 
6329       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6330       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6331       /* A quad */
6332       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6333       orntNew[0] = ornt[0];
6334       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6335       orntNew[1] = 0;
6336       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6337       orntNew[2] = -2;
6338       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6339       orntNew[3] = ornt[3];
6340       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6341       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6342 #if 1
6343       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6344       for (p = 0; p < 4; ++p) {
6345         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6346       }
6347 #endif
6348       /* B quad */
6349       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6350       orntNew[0] = ornt[0];
6351       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6352       orntNew[1] = ornt[1];
6353       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6354       orntNew[2] = 0;
6355       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6356       orntNew[3] = -2;
6357       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6358       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6359 #if 1
6360       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6361       for (p = 0; p < 4; ++p) {
6362         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6363       }
6364 #endif
6365       /* C quad */
6366       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6367       orntNew[0] = -2;
6368       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6369       orntNew[1] = ornt[1];
6370       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6371       orntNew[2] = ornt[2];
6372       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6373       orntNew[3] = 0;
6374       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6375       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6376 #if 1
6377       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6378       for (p = 0; p < 4; ++p) {
6379         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6380       }
6381 #endif
6382       /* D quad */
6383       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6384       orntNew[0] = 0;
6385       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6386       orntNew[1] = -2;
6387       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6388       orntNew[2] = ornt[2];
6389       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6390       orntNew[3] = ornt[3];
6391       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6392       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6393 #if 1
6394       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6395       for (p = 0; p < 4; ++p) {
6396         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6397       }
6398 #endif
6399     }
6400     /* Split faces have 2 vertices and the same cells as the parent */
6401     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6402     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6403     for (f = fStart; f < fEnd; ++f) {
6404       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6405 
6406       for (r = 0; r < 2; ++r) {
6407         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6408         const PetscInt *cone, *support;
6409         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6410 
6411         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6412         coneNew[0]       = vStartNew + (cone[0] - vStart);
6413         coneNew[1]       = vStartNew + (cone[1] - vStart);
6414         coneNew[(r+1)%2] = newv;
6415         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6416 #if 1
6417         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6418         for (p = 0; p < 2; ++p) {
6419           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6420         }
6421 #endif
6422         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6423         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6424         for (s = 0; s < supportSize; ++s) {
6425           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6426           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6427           for (c = 0; c < coneSize; ++c) {
6428             if (cone[c] == f) break;
6429           }
6430           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6431         }
6432         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6433 #if 1
6434         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6435         for (p = 0; p < supportSize; ++p) {
6436           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6437         }
6438 #endif
6439       }
6440     }
6441     /* Interior faces have 2 vertices and 2 cells */
6442     for (c = cStart; c < cEnd; ++c) {
6443       const PetscInt *cone;
6444       PetscInt        coneNew[2], supportNew[2];
6445 
6446       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6447       for (r = 0; r < 4; ++r) {
6448         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6449 
6450         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6451         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6452         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6453 #if 1
6454         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6455         for (p = 0; p < 2; ++p) {
6456           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6457         }
6458 #endif
6459         supportNew[0] = (c - cStart)*4 + r;
6460         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6461         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6462 #if 1
6463         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6464         for (p = 0; p < 2; ++p) {
6465           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6466         }
6467 #endif
6468       }
6469     }
6470     /* Old vertices have identical supports */
6471     for (v = vStart; v < vEnd; ++v) {
6472       const PetscInt  newp = vStartNew + (v - vStart);
6473       const PetscInt *support, *cone;
6474       PetscInt        size, s;
6475 
6476       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6477       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6478       for (s = 0; s < size; ++s) {
6479         PetscInt r = 0;
6480 
6481         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6482         if (cone[1] == v) r = 1;
6483         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6484       }
6485       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6486 #if 1
6487       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6488       for (p = 0; p < size; ++p) {
6489         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6490       }
6491 #endif
6492     }
6493     /* Face vertices have 2 + cells supports */
6494     for (f = fStart; f < fEnd; ++f) {
6495       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6496       const PetscInt *cone, *support;
6497       PetscInt        size, s;
6498 
6499       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6500       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6501       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6502       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6503       for (s = 0; s < size; ++s) {
6504         PetscInt r = 0;
6505 
6506         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6507         if      (cone[1] == f) r = 1;
6508         else if (cone[2] == f) r = 2;
6509         else if (cone[3] == f) r = 3;
6510         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6511       }
6512       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6513 #if 1
6514       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6515       for (p = 0; p < 2+size; ++p) {
6516         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6517       }
6518 #endif
6519     }
6520     /* Cell vertices have 4 supports */
6521     for (c = cStart; c < cEnd; ++c) {
6522       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6523       PetscInt       supportNew[4];
6524 
6525       for (r = 0; r < 4; ++r) {
6526         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6527       }
6528       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6529     }
6530     break;
6531   case 3:
6532     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6533     cMax = PetscMin(cEnd, cMax);
6534     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6535     fMax = PetscMin(fEnd, fMax);
6536     /* Interior cells have 3 faces */
6537     for (c = cStart; c < cMax; ++c) {
6538       const PetscInt  newp = cStartNew + (c - cStart)*4;
6539       const PetscInt *cone, *ornt;
6540       PetscInt        coneNew[3], orntNew[3];
6541 
6542       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6543       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6544       /* A triangle */
6545       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6546       orntNew[0] = ornt[0];
6547       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6548       orntNew[1] = -2;
6549       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6550       orntNew[2] = ornt[2];
6551       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6552       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6553 #if 1
6554       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6555       for (p = 0; p < 3; ++p) {
6556         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6557       }
6558 #endif
6559       /* B triangle */
6560       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6561       orntNew[0] = ornt[0];
6562       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6563       orntNew[1] = ornt[1];
6564       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6565       orntNew[2] = -2;
6566       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6567       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6568 #if 1
6569       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6570       for (p = 0; p < 3; ++p) {
6571         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6572       }
6573 #endif
6574       /* C triangle */
6575       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6576       orntNew[0] = -2;
6577       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6578       orntNew[1] = ornt[1];
6579       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6580       orntNew[2] = ornt[2];
6581       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6582       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6583 #if 1
6584       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6585       for (p = 0; p < 3; ++p) {
6586         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6587       }
6588 #endif
6589       /* D triangle */
6590       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6591       orntNew[0] = 0;
6592       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6593       orntNew[1] = 0;
6594       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6595       orntNew[2] = 0;
6596       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6597       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6598 #if 1
6599       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6600       for (p = 0; p < 3; ++p) {
6601         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6602       }
6603 #endif
6604     }
6605     /*
6606      2----3----3
6607      |         |
6608      |    B    |
6609      |         |
6610      0----4--- 1
6611      |         |
6612      |    A    |
6613      |         |
6614      0----2----1
6615      */
6616     /* Hybrid cells have 4 faces */
6617     for (c = cMax; c < cEnd; ++c) {
6618       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6619       const PetscInt *cone, *ornt;
6620       PetscInt        coneNew[4], orntNew[4];
6621 
6622       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6623       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6624       /* A quad */
6625       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6626       orntNew[0] = ornt[0];
6627       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6628       orntNew[1] = ornt[1];
6629       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6630       orntNew[2] = 0;
6631       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6632       orntNew[3] = 0;
6633       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6634       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6635 #if 1
6636       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6637       for (p = 0; p < 4; ++p) {
6638         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6639       }
6640 #endif
6641       /* B quad */
6642       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6643       orntNew[0] = ornt[0];
6644       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6645       orntNew[1] = ornt[1];
6646       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6647       orntNew[2] = 0;
6648       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6649       orntNew[3] = 0;
6650       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6651       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6652 #if 1
6653       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6654       for (p = 0; p < 4; ++p) {
6655         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6656       }
6657 #endif
6658     }
6659     /* Interior split faces have 2 vertices and the same cells as the parent */
6660     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6661     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6662     for (f = fStart; f < fMax; ++f) {
6663       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6664 
6665       for (r = 0; r < 2; ++r) {
6666         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6667         const PetscInt *cone, *support;
6668         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6669 
6670         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6671         coneNew[0]       = vStartNew + (cone[0] - vStart);
6672         coneNew[1]       = vStartNew + (cone[1] - vStart);
6673         coneNew[(r+1)%2] = newv;
6674         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6675 #if 1
6676         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6677         for (p = 0; p < 2; ++p) {
6678           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6679         }
6680 #endif
6681         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6682         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6683         for (s = 0; s < supportSize; ++s) {
6684           if (support[s] >= cMax) {
6685             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6686           } else {
6687             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6688             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6689             for (c = 0; c < coneSize; ++c) {
6690               if (cone[c] == f) break;
6691             }
6692             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6693           }
6694         }
6695         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6696 #if 1
6697         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6698         for (p = 0; p < supportSize; ++p) {
6699           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6700         }
6701 #endif
6702       }
6703     }
6704     /* Interior cell faces have 2 vertices and 2 cells */
6705     for (c = cStart; c < cMax; ++c) {
6706       const PetscInt *cone;
6707 
6708       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6709       for (r = 0; r < 3; ++r) {
6710         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6711         PetscInt       coneNew[2];
6712         PetscInt       supportNew[2];
6713 
6714         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6715         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6716         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6717 #if 1
6718         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6719         for (p = 0; p < 2; ++p) {
6720           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6721         }
6722 #endif
6723         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6724         supportNew[1] = (c - cStart)*4 + 3;
6725         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6726 #if 1
6727         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6728         for (p = 0; p < 2; ++p) {
6729           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6730         }
6731 #endif
6732       }
6733     }
6734     /* Interior hybrid faces have 2 vertices and the same cells */
6735     for (f = fMax; f < fEnd; ++f) {
6736       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6737       const PetscInt *cone;
6738       const PetscInt *support;
6739       PetscInt        coneNew[2];
6740       PetscInt        supportNew[2];
6741       PetscInt        size, s, r;
6742 
6743       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6744       coneNew[0] = vStartNew + (cone[0] - vStart);
6745       coneNew[1] = vStartNew + (cone[1] - vStart);
6746       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6747 #if 1
6748       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6749       for (p = 0; p < 2; ++p) {
6750         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6751       }
6752 #endif
6753       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6754       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6755       for (s = 0; s < size; ++s) {
6756         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6757         for (r = 0; r < 2; ++r) {
6758           if (cone[r+2] == f) break;
6759         }
6760         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6761       }
6762       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6763 #if 1
6764       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6765       for (p = 0; p < size; ++p) {
6766         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6767       }
6768 #endif
6769     }
6770     /* Cell hybrid faces have 2 vertices and 2 cells */
6771     for (c = cMax; c < cEnd; ++c) {
6772       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6773       const PetscInt *cone;
6774       PetscInt        coneNew[2];
6775       PetscInt        supportNew[2];
6776 
6777       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6778       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6779       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6780       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6781 #if 1
6782       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6783       for (p = 0; p < 2; ++p) {
6784         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6785       }
6786 #endif
6787       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6788       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6789       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6790 #if 1
6791       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6792       for (p = 0; p < 2; ++p) {
6793         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6794       }
6795 #endif
6796     }
6797     /* Old vertices have identical supports */
6798     for (v = vStart; v < vEnd; ++v) {
6799       const PetscInt  newp = vStartNew + (v - vStart);
6800       const PetscInt *support, *cone;
6801       PetscInt        size, s;
6802 
6803       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6804       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6805       for (s = 0; s < size; ++s) {
6806         if (support[s] >= fMax) {
6807           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6808         } else {
6809           PetscInt r = 0;
6810 
6811           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6812           if (cone[1] == v) r = 1;
6813           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6814         }
6815       }
6816       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6817 #if 1
6818       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6819       for (p = 0; p < size; ++p) {
6820         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6821       }
6822 #endif
6823     }
6824     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6825     for (f = fStart; f < fMax; ++f) {
6826       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6827       const PetscInt *cone, *support;
6828       PetscInt        size, newSize = 2, s;
6829 
6830       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6831       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6832       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6833       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6834       for (s = 0; s < size; ++s) {
6835         PetscInt r = 0;
6836 
6837         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6838         if (support[s] >= cMax) {
6839           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6840 
6841           newSize += 1;
6842         } else {
6843           if      (cone[1] == f) r = 1;
6844           else if (cone[2] == f) r = 2;
6845           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6846           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6847 
6848           newSize += 2;
6849         }
6850       }
6851       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6852 #if 1
6853       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6854       for (p = 0; p < newSize; ++p) {
6855         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6856       }
6857 #endif
6858     }
6859     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6860     break;
6861   default:
6862     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6863   }
6864   PetscFunctionReturn(0);
6865 }
6866 
6867 #undef __FUNCT__
6868 #define __FUNCT__ "CellRefinerSetCoordinates"
6869 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6870 {
6871   PetscSection   coordSection, coordSectionNew;
6872   Vec            coordinates, coordinatesNew;
6873   PetscScalar   *coords, *coordsNew;
6874   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6875   PetscErrorCode ierr;
6876 
6877   PetscFunctionBegin;
6878   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6879   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6880   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6881   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6882   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6883   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6884   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6885   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6886   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6887   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6888   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6889   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6890   if (fMax < 0) fMax = fEnd;
6891   switch (refiner) {
6892   case 1:
6893   case 2:
6894   case 3:
6895     /* Simplicial and Hex 2D */
6896     /* All vertices have the dim coordinates */
6897     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6898       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6899       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6900     }
6901     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6902     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6903     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6904     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6905     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6906     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6907     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6908     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6909     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6910     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6911     /* Old vertices have the same coordinates */
6912     for (v = vStart; v < vEnd; ++v) {
6913       const PetscInt newv = vStartNew + (v - vStart);
6914       PetscInt       off, offnew, d;
6915 
6916       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6917       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6918       for (d = 0; d < dim; ++d) {
6919         coordsNew[offnew+d] = coords[off+d];
6920       }
6921     }
6922     /* Face vertices have the average of endpoint coordinates */
6923     for (f = fStart; f < fMax; ++f) {
6924       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6925       const PetscInt *cone;
6926       PetscInt        coneSize, offA, offB, offnew, d;
6927 
6928       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6929       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6930       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6931       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6932       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6933       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6934       for (d = 0; d < dim; ++d) {
6935         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6936       }
6937     }
6938     /* Just Hex 2D */
6939     if (refiner == 2) {
6940       /* Cell vertices have the average of corner coordinates */
6941       for (c = cStart; c < cEnd; ++c) {
6942         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6943         PetscInt      *cone = PETSC_NULL;
6944         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6945 
6946         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6947         for (p = 0; p < closureSize*2; p += 2) {
6948           const PetscInt point = cone[p];
6949           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6950         }
6951         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6952         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6953         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6954         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6955         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6956         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6957         for (d = 0; d < dim; ++d) {
6958           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6959         }
6960         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6961       }
6962     }
6963     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6964     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6965     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6966     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6967     break;
6968   default:
6969     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6970   }
6971   PetscFunctionReturn(0);
6972 }
6973 
6974 #undef __FUNCT__
6975 #define __FUNCT__ "DMPlexCreateProcessSF"
6976 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6977 {
6978   PetscInt           numRoots, numLeaves, l;
6979   const PetscInt    *localPoints;
6980   const PetscSFNode *remotePoints;
6981   PetscInt          *localPointsNew;
6982   PetscSFNode       *remotePointsNew;
6983   PetscInt          *ranks, *ranksNew;
6984   PetscErrorCode     ierr;
6985 
6986   PetscFunctionBegin;
6987   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6988   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6989   for (l = 0; l < numLeaves; ++l) {
6990     ranks[l] = remotePoints[l].rank;
6991   }
6992   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6993   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6994   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6995   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6996   for (l = 0; l < numLeaves; ++l) {
6997     ranksNew[l]              = ranks[l];
6998     localPointsNew[l]        = l;
6999     remotePointsNew[l].index = 0;
7000     remotePointsNew[l].rank  = ranksNew[l];
7001   }
7002   ierr = PetscFree(ranks);CHKERRQ(ierr);
7003   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
7004   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
7005   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7006   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7007   PetscFunctionReturn(0);
7008 }
7009 
7010 #undef __FUNCT__
7011 #define __FUNCT__ "CellRefinerCreateSF"
7012 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7013 {
7014   PetscSF            sf, sfNew, sfProcess;
7015   IS                 processRanks;
7016   MPI_Datatype       depthType;
7017   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7018   const PetscInt    *localPoints, *neighbors;
7019   const PetscSFNode *remotePoints;
7020   PetscInt          *localPointsNew;
7021   PetscSFNode       *remotePointsNew;
7022   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7023   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7024   PetscErrorCode     ierr;
7025 
7026   PetscFunctionBegin;
7027   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7028   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7029   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7030   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7031   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7032   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7033   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7034   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7035   switch (refiner) {
7036   case 3:
7037     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7038     cMax = PetscMin(cEnd, cMax);
7039     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7040     fMax = PetscMin(fEnd, fMax);
7041   }
7042   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7043   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7044   /* Caculate size of new SF */
7045   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7046   if (numRoots < 0) PetscFunctionReturn(0);
7047   for (l = 0; l < numLeaves; ++l) {
7048     const PetscInt p = localPoints[l];
7049 
7050     switch (refiner) {
7051     case 1:
7052       /* Simplicial 2D */
7053       if ((p >= vStart) && (p < vEnd)) {
7054         /* Old vertices stay the same */
7055         ++numLeavesNew;
7056       } else if ((p >= fStart) && (p < fEnd)) {
7057         /* Old faces add new faces and vertex */
7058         numLeavesNew += 1 + 2;
7059       } else if ((p >= cStart) && (p < cEnd)) {
7060         /* Old cells add new cells and interior faces */
7061         numLeavesNew += 4 + 3;
7062       }
7063       break;
7064     case 2:
7065       /* Hex 2D */
7066       if ((p >= vStart) && (p < vEnd)) {
7067         /* Old vertices stay the same */
7068         ++numLeavesNew;
7069       } else if ((p >= fStart) && (p < fEnd)) {
7070         /* Old faces add new faces and vertex */
7071         numLeavesNew += 1 + 2;
7072       } else if ((p >= cStart) && (p < cEnd)) {
7073         /* Old cells add new cells and interior faces */
7074         numLeavesNew += 4 + 4;
7075       }
7076       break;
7077     default:
7078       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7079     }
7080   }
7081   /* Communicate depthSizes for each remote rank */
7082   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7083   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7084   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7085   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);
7086   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7087   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7088   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7089   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7090   for (n = 0; n < numNeighbors; ++n) {
7091     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7092   }
7093   depthSizeOld[depth]   = cMax;
7094   depthSizeOld[0]       = vMax;
7095   depthSizeOld[depth-1] = fMax;
7096   depthSizeOld[1]       = eMax;
7097 
7098   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7099   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7100 
7101   depthSizeOld[depth]   = cEnd - cStart;
7102   depthSizeOld[0]       = vEnd - vStart;
7103   depthSizeOld[depth-1] = fEnd - fStart;
7104   depthSizeOld[1]       = eEnd - eStart;
7105 
7106   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7107   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7108   for (n = 0; n < numNeighbors; ++n) {
7109     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7110   }
7111   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7112   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7113   /* Calculate new point SF */
7114   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7115   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7116   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7117   for (l = 0, m = 0; l < numLeaves; ++l) {
7118     PetscInt    p     = localPoints[l];
7119     PetscInt    rp    = remotePoints[l].index, n;
7120     PetscMPIInt rrank = remotePoints[l].rank;
7121 
7122     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7123     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7124     switch (refiner) {
7125     case 1:
7126       /* Simplicial 2D */
7127       if ((p >= vStart) && (p < vEnd)) {
7128         /* Old vertices stay the same */
7129         localPointsNew[m]        = vStartNew     + (p  - vStart);
7130         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7131         remotePointsNew[m].rank  = rrank;
7132         ++m;
7133       } else if ((p >= fStart) && (p < fEnd)) {
7134         /* Old faces add new faces and vertex */
7135         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7136         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7137         remotePointsNew[m].rank  = rrank;
7138         ++m;
7139         for (r = 0; r < 2; ++r, ++m) {
7140           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7141           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7142           remotePointsNew[m].rank  = rrank;
7143         }
7144       } else if ((p >= cStart) && (p < cEnd)) {
7145         /* Old cells add new cells and interior faces */
7146         for (r = 0; r < 4; ++r, ++m) {
7147           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7148           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7149           remotePointsNew[m].rank  = rrank;
7150         }
7151         for (r = 0; r < 3; ++r, ++m) {
7152           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7153           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7154           remotePointsNew[m].rank  = rrank;
7155         }
7156       }
7157       break;
7158     case 2:
7159       /* Hex 2D */
7160       if ((p >= vStart) && (p < vEnd)) {
7161         /* Old vertices stay the same */
7162         localPointsNew[m]        = vStartNew     + (p  - vStart);
7163         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7164         remotePointsNew[m].rank  = rrank;
7165         ++m;
7166       } else if ((p >= fStart) && (p < fEnd)) {
7167         /* Old faces add new faces and vertex */
7168         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7169         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7170         remotePointsNew[m].rank  = rrank;
7171         ++m;
7172         for (r = 0; r < 2; ++r, ++m) {
7173           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7174           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7175           remotePointsNew[m].rank  = rrank;
7176         }
7177       } else if ((p >= cStart) && (p < cEnd)) {
7178         /* Old cells add new cells and interior faces */
7179         for (r = 0; r < 4; ++r, ++m) {
7180           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7181           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7182           remotePointsNew[m].rank  = rrank;
7183         }
7184         for (r = 0; r < 4; ++r, ++m) {
7185           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7186           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7187           remotePointsNew[m].rank  = rrank;
7188         }
7189       }
7190       break;
7191     case 3:
7192       /* Hybrid simplicial 2D */
7193       if ((p >= vStart) && (p < vEnd)) {
7194         /* Old vertices stay the same */
7195         localPointsNew[m]        = vStartNew     + (p  - vStart);
7196         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7197         remotePointsNew[m].rank  = rrank;
7198         ++m;
7199       } else if ((p >= fStart) && (p < fMax)) {
7200         /* Old interior faces add new faces and vertex */
7201         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7202         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7203         remotePointsNew[m].rank  = rrank;
7204         ++m;
7205         for (r = 0; r < 2; ++r, ++m) {
7206           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7207           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7208           remotePointsNew[m].rank  = rrank;
7209         }
7210       } else if ((p >= fMax) && (p < fEnd)) {
7211         /* Old hybrid faces stay the same */
7212         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7213         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7214         remotePointsNew[m].rank  = rrank;
7215         ++m;
7216       } else if ((p >= cStart) && (p < cMax)) {
7217         /* Old interior cells add new cells and interior faces */
7218         for (r = 0; r < 4; ++r, ++m) {
7219           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7220           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7221           remotePointsNew[m].rank  = rrank;
7222         }
7223         for (r = 0; r < 3; ++r, ++m) {
7224           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7225           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7226           remotePointsNew[m].rank  = rrank;
7227         }
7228       } else if ((p >= cStart) && (p < cMax)) {
7229         /* Old hybrid cells add new cells and hybrid face */
7230         for (r = 0; r < 2; ++r, ++m) {
7231           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7232           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7233           remotePointsNew[m].rank  = rrank;
7234         }
7235         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7236         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]);
7237         remotePointsNew[m].rank  = rrank;
7238         ++m;
7239       }
7240       break;
7241     default:
7242       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7243     }
7244   }
7245   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7246   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7247   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7248   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7249   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7250   PetscFunctionReturn(0);
7251 }
7252 
7253 #undef __FUNCT__
7254 #define __FUNCT__ "CellRefinerCreateLabels"
7255 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7256 {
7257   PetscInt       numLabels, l;
7258   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7259   PetscErrorCode ierr;
7260 
7261   PetscFunctionBegin;
7262   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7263   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7264   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7265   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7266 
7267   cStartNew = 0;
7268   vStartNew = depthSize[2];
7269   fStartNew = depthSize[2] + depthSize[0];
7270 
7271   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7272   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7273   switch (refiner) {
7274   case 3:
7275     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7276     cMax = PetscMin(cEnd, cMax);
7277     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7278     fMax = PetscMin(fEnd, fMax);
7279   }
7280   for (l = 0; l < numLabels; ++l) {
7281     DMLabel         label, labelNew;
7282     const char     *lname;
7283     PetscBool       isDepth;
7284     IS              valueIS;
7285     const PetscInt *values;
7286     PetscInt        numValues, val;
7287 
7288     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7289     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7290     if (isDepth) continue;
7291     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7292     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7293     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7294     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7295     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7296     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7297     for (val = 0; val < numValues; ++val) {
7298       IS              pointIS;
7299       const PetscInt *points;
7300       PetscInt        numPoints, n;
7301 
7302       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7303       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7304       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7305       for (n = 0; n < numPoints; ++n) {
7306         const PetscInt p = points[n];
7307         switch (refiner) {
7308         case 1:
7309           /* Simplicial 2D */
7310           if ((p >= vStart) && (p < vEnd)) {
7311             /* Old vertices stay the same */
7312             newp = vStartNew + (p - vStart);
7313             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7314           } else if ((p >= fStart) && (p < fEnd)) {
7315             /* Old faces add new faces and vertex */
7316             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7317             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7318             for (r = 0; r < 2; ++r) {
7319               newp = fStartNew + (p - fStart)*2 + r;
7320               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7321             }
7322           } else if ((p >= cStart) && (p < cEnd)) {
7323             /* Old cells add new cells and interior faces */
7324             for (r = 0; r < 4; ++r) {
7325               newp = cStartNew + (p - cStart)*4 + r;
7326               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7327             }
7328             for (r = 0; r < 3; ++r) {
7329               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7330               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7331             }
7332           }
7333           break;
7334         case 2:
7335           /* Hex 2D */
7336           if ((p >= vStart) && (p < vEnd)) {
7337             /* Old vertices stay the same */
7338             newp = vStartNew + (p - vStart);
7339             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7340           } else if ((p >= fStart) && (p < fEnd)) {
7341             /* Old faces add new faces and vertex */
7342             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7343             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7344             for (r = 0; r < 2; ++r) {
7345               newp = fStartNew + (p - fStart)*2 + r;
7346               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7347             }
7348           } else if ((p >= cStart) && (p < cEnd)) {
7349             /* Old cells add new cells and interior faces and vertex */
7350             for (r = 0; r < 4; ++r) {
7351               newp = cStartNew + (p - cStart)*4 + r;
7352               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7353             }
7354             for (r = 0; r < 4; ++r) {
7355               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7356               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7357             }
7358             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7359             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7360           }
7361           break;
7362         case 3:
7363           /* Hybrid simplicial 2D */
7364           if ((p >= vStart) && (p < vEnd)) {
7365             /* Old vertices stay the same */
7366             newp = vStartNew + (p - vStart);
7367             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7368           } else if ((p >= fStart) && (p < fMax)) {
7369             /* Old interior faces add new faces and vertex */
7370             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7371             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7372             for (r = 0; r < 2; ++r) {
7373               newp = fStartNew + (p - fStart)*2 + r;
7374               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7375             }
7376           } else if ((p >= fMax) && (p < fEnd)) {
7377             /* Old hybrid faces stay the same */
7378             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7379             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7380           } else if ((p >= cStart) && (p < cMax)) {
7381             /* Old interior cells add new cells and interior faces */
7382             for (r = 0; r < 4; ++r) {
7383               newp = cStartNew + (p - cStart)*4 + r;
7384               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7385             }
7386             for (r = 0; r < 3; ++r) {
7387               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7388               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7389             }
7390           } else if ((p >= cMax) && (p < cEnd)) {
7391             /* Old hybrid cells add new cells and hybrid face */
7392             for (r = 0; r < 2; ++r) {
7393               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7394               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7395             }
7396             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7397             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7398           }
7399           break;
7400         default:
7401           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7402         }
7403       }
7404       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7405       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7406     }
7407     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7408     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7409     if (0) {
7410       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7411       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7412       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7413     }
7414   }
7415   PetscFunctionReturn(0);
7416 }
7417 
7418 #undef __FUNCT__
7419 #define __FUNCT__ "DMPlexRefine_Uniform"
7420 /* This will only work for interpolated meshes */
7421 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7422 {
7423   DM             rdm;
7424   PetscInt      *depthSize;
7425   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7426   PetscErrorCode ierr;
7427 
7428   PetscFunctionBegin;
7429   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7430   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7431   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7432   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7433   /* Calculate number of new points of each depth */
7434   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7435   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7436   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7437   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7438   /* Step 1: Set chart */
7439   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7440   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7441   /* Step 2: Set cone/support sizes */
7442   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7443   /* Step 3: Setup refined DM */
7444   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7445   /* Step 4: Set cones and supports */
7446   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7447   /* Step 5: Stratify */
7448   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7449   /* Step 6: Set coordinates for vertices */
7450   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7451   /* Step 7: Create pointSF */
7452   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7453   /* Step 8: Create labels */
7454   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7455   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7456 
7457   *dmRefined = rdm;
7458   PetscFunctionReturn(0);
7459 }
7460 
7461 #undef __FUNCT__
7462 #define __FUNCT__ "DMPlexSetRefinementUniform"
7463 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7464 {
7465   DM_Plex *mesh = (DM_Plex*) dm->data;
7466 
7467   PetscFunctionBegin;
7468   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7469   mesh->refinementUniform = refinementUniform;
7470   PetscFunctionReturn(0);
7471 }
7472 
7473 #undef __FUNCT__
7474 #define __FUNCT__ "DMPlexGetRefinementUniform"
7475 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7476 {
7477   DM_Plex *mesh = (DM_Plex*) dm->data;
7478 
7479   PetscFunctionBegin;
7480   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7481   PetscValidPointer(refinementUniform,  2);
7482   *refinementUniform = mesh->refinementUniform;
7483   PetscFunctionReturn(0);
7484 }
7485 
7486 #undef __FUNCT__
7487 #define __FUNCT__ "DMPlexSetRefinementLimit"
7488 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7489 {
7490   DM_Plex *mesh = (DM_Plex*) dm->data;
7491 
7492   PetscFunctionBegin;
7493   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7494   mesh->refinementLimit = refinementLimit;
7495   PetscFunctionReturn(0);
7496 }
7497 
7498 #undef __FUNCT__
7499 #define __FUNCT__ "DMPlexGetRefinementLimit"
7500 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7501 {
7502   DM_Plex *mesh = (DM_Plex*) dm->data;
7503 
7504   PetscFunctionBegin;
7505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7506   PetscValidPointer(refinementLimit,  2);
7507   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7508   *refinementLimit = mesh->refinementLimit;
7509   PetscFunctionReturn(0);
7510 }
7511 
7512 #undef __FUNCT__
7513 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7514 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7515 {
7516   PetscInt       dim, cStart, coneSize, cMax;
7517   PetscErrorCode ierr;
7518 
7519   PetscFunctionBegin;
7520   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7521   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7522   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7523   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7524   switch (dim) {
7525   case 2:
7526     switch (coneSize) {
7527     case 3:
7528       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7529       else *cellRefiner = 1; /* Triangular */
7530       break;
7531     case 4:
7532       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7533       else *cellRefiner = 2; /* Quadrilateral */
7534       break;
7535     default:
7536       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7537     }
7538     break;
7539   default:
7540     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7541   }
7542   PetscFunctionReturn(0);
7543 }
7544 
7545 #undef __FUNCT__
7546 #define __FUNCT__ "DMRefine_Plex"
7547 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7548 {
7549   PetscReal      refinementLimit;
7550   PetscInt       dim, cStart, cEnd;
7551   char           genname[1024], *name = PETSC_NULL;
7552   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7553   PetscErrorCode ierr;
7554 
7555   PetscFunctionBegin;
7556   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7557   if (isUniform) {
7558     CellRefiner cellRefiner;
7559 
7560     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7561     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7562     PetscFunctionReturn(0);
7563   }
7564   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7565   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7566   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7567   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7568   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7569   if (flg) name = genname;
7570   if (name) {
7571     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7572     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7573     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7574   }
7575   switch (dim) {
7576   case 2:
7577     if (!name || isTriangle) {
7578 #if defined(PETSC_HAVE_TRIANGLE)
7579       double  *maxVolumes;
7580       PetscInt c;
7581 
7582       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7583       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7584       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7585 #else
7586       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7587 #endif
7588     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7589     break;
7590   case 3:
7591     if (!name || isCTetgen) {
7592 #if defined(PETSC_HAVE_CTETGEN)
7593       PetscReal *maxVolumes;
7594       PetscInt   c;
7595 
7596       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7597       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7598       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7599 #else
7600       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7601 #endif
7602     } else if (isTetgen) {
7603 #if defined(PETSC_HAVE_TETGEN)
7604       double  *maxVolumes;
7605       PetscInt c;
7606 
7607       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7608       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7609       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7610 #else
7611       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7612 #endif
7613     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7614     break;
7615   default:
7616     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7617   }
7618   PetscFunctionReturn(0);
7619 }
7620 
7621 #undef __FUNCT__
7622 #define __FUNCT__ "DMPlexGetDepth"
7623 /*@
7624   DMPlexGetDepth - get the number of strata
7625 
7626   Not Collective
7627 
7628   Input Parameters:
7629 . dm           - The DMPlex object
7630 
7631   Output Parameters:
7632 . depth - number of strata
7633 
7634   Level: developer
7635 
7636   Notes:
7637   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7638 
7639 .keywords: mesh, points
7640 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7641 @*/
7642 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7643 {
7644   PetscInt       d;
7645   PetscErrorCode ierr;
7646 
7647   PetscFunctionBegin;
7648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7649   PetscValidPointer(depth, 2);
7650   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7651   *depth = d-1;
7652   PetscFunctionReturn(0);
7653 }
7654 
7655 #undef __FUNCT__
7656 #define __FUNCT__ "DMPlexGetDepthStratum"
7657 /*@
7658   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7659 
7660   Not Collective
7661 
7662   Input Parameters:
7663 + dm           - The DMPlex object
7664 - stratumValue - The requested depth
7665 
7666   Output Parameters:
7667 + start - The first point at this depth
7668 - end   - One beyond the last point at this depth
7669 
7670   Level: developer
7671 
7672 .keywords: mesh, points
7673 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7674 @*/
7675 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7676 {
7677   DM_Plex       *mesh = (DM_Plex*) dm->data;
7678   DMLabel        next  = mesh->labels;
7679   PetscBool      flg   = PETSC_FALSE;
7680   PetscInt       depth;
7681   PetscErrorCode ierr;
7682 
7683   PetscFunctionBegin;
7684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7685   if (stratumValue < 0) {
7686     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7687     PetscFunctionReturn(0);
7688   } else {
7689     PetscInt pStart, pEnd;
7690 
7691     if (start) *start = 0;
7692     if (end)   *end   = 0;
7693     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7694     if (pStart == pEnd) PetscFunctionReturn(0);
7695   }
7696   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7697   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7698   /* We should have a generic GetLabel() and a Label class */
7699   while (next) {
7700     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7701     if (flg) break;
7702     next = next->next;
7703   }
7704   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7705   depth = stratumValue;
7706   if ((depth < 0) || (depth >= next->numStrata)) {
7707     if (start) *start = 0;
7708     if (end)   *end   = 0;
7709   } else {
7710     if (start) *start = next->points[next->stratumOffsets[depth]];
7711     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7712   }
7713   PetscFunctionReturn(0);
7714 }
7715 
7716 #undef __FUNCT__
7717 #define __FUNCT__ "DMPlexGetHeightStratum"
7718 /*@
7719   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7720 
7721   Not Collective
7722 
7723   Input Parameters:
7724 + dm           - The DMPlex object
7725 - stratumValue - The requested height
7726 
7727   Output Parameters:
7728 + start - The first point at this height
7729 - end   - One beyond the last point at this height
7730 
7731   Level: developer
7732 
7733 .keywords: mesh, points
7734 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7735 @*/
7736 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7737 {
7738   DM_Plex       *mesh = (DM_Plex*) dm->data;
7739   DMLabel        next  = mesh->labels;
7740   PetscBool      flg   = PETSC_FALSE;
7741   PetscInt       depth;
7742   PetscErrorCode ierr;
7743 
7744   PetscFunctionBegin;
7745   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7746   if (stratumValue < 0) {
7747     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7748   } else {
7749     PetscInt pStart, pEnd;
7750 
7751     if (start) *start = 0;
7752     if (end)   *end   = 0;
7753     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7754     if (pStart == pEnd) PetscFunctionReturn(0);
7755   }
7756   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7757   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7758   /* We should have a generic GetLabel() and a Label class */
7759   while (next) {
7760     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7761     if (flg) break;
7762     next = next->next;
7763   }
7764   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7765   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7766   if ((depth < 0) || (depth >= next->numStrata)) {
7767     if (start) *start = 0;
7768     if (end)   *end   = 0;
7769   } else {
7770     if (start) *start = next->points[next->stratumOffsets[depth]];
7771     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7772   }
7773   PetscFunctionReturn(0);
7774 }
7775 
7776 #undef __FUNCT__
7777 #define __FUNCT__ "DMPlexCreateSectionInitial"
7778 /* Set the number of dof on each point and separate by fields */
7779 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7780 {
7781   PetscInt      *numDofTot;
7782   PetscInt       pStart = 0, pEnd = 0;
7783   PetscInt       p, d, f;
7784   PetscErrorCode ierr;
7785 
7786   PetscFunctionBegin;
7787   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7788   for (d = 0; d <= dim; ++d) {
7789     numDofTot[d] = 0;
7790     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7791   }
7792   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7793   if (numFields > 0) {
7794     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7795     if (numComp) {
7796       for (f = 0; f < numFields; ++f) {
7797         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7798       }
7799     }
7800   }
7801   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7802   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7803   for (d = 0; d <= dim; ++d) {
7804     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7805     for (p = pStart; p < pEnd; ++p) {
7806       for (f = 0; f < numFields; ++f) {
7807         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7808       }
7809       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7810     }
7811   }
7812   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7813   PetscFunctionReturn(0);
7814 }
7815 
7816 #undef __FUNCT__
7817 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7818 /* Set the number of dof on each point and separate by fields
7819    If constDof is PETSC_DETERMINE, constrain every dof on the point
7820 */
7821 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7822 {
7823   PetscInt       numFields;
7824   PetscInt       bc;
7825   PetscErrorCode ierr;
7826 
7827   PetscFunctionBegin;
7828   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7829   for (bc = 0; bc < numBC; ++bc) {
7830     PetscInt        field = 0;
7831     const PetscInt *idx;
7832     PetscInt        n, i;
7833 
7834     if (numFields) field = bcField[bc];
7835     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7836     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7837     for (i = 0; i < n; ++i) {
7838       const PetscInt p        = idx[i];
7839       PetscInt       numConst = constDof;
7840 
7841       /* Constrain every dof on the point */
7842       if (numConst < 0) {
7843         if (numFields) {
7844           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7845         } else {
7846           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7847         }
7848       }
7849       if (numFields) {
7850         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7851       }
7852       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7853     }
7854     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7855   }
7856   PetscFunctionReturn(0);
7857 }
7858 
7859 #undef __FUNCT__
7860 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7861 /* Set the constrained indices on each point and separate by fields */
7862 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7863 {
7864   PetscInt      *maxConstraints;
7865   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7866   PetscErrorCode ierr;
7867 
7868   PetscFunctionBegin;
7869   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7870   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7871   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7872   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7873   for (p = pStart; p < pEnd; ++p) {
7874     PetscInt cdof;
7875 
7876     if (numFields) {
7877       for (f = 0; f < numFields; ++f) {
7878         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7879         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7880       }
7881     } else {
7882       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7883       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7884     }
7885   }
7886   for (f = 0; f < numFields; ++f) {
7887     maxConstraints[numFields] += maxConstraints[f];
7888   }
7889   if (maxConstraints[numFields]) {
7890     PetscInt *indices;
7891 
7892     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7893     for (p = pStart; p < pEnd; ++p) {
7894       PetscInt cdof, d;
7895 
7896       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7897       if (cdof) {
7898         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7899         if (numFields) {
7900           PetscInt numConst = 0, foff = 0;
7901 
7902           for (f = 0; f < numFields; ++f) {
7903             PetscInt cfdof, fdof;
7904 
7905             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7906             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7907             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7908             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7909             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7910             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7911             numConst += cfdof;
7912             foff     += fdof;
7913           }
7914           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7915         } else {
7916           for (d = 0; d < cdof; ++d) indices[d] = d;
7917         }
7918         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7919       }
7920     }
7921     ierr = PetscFree(indices);CHKERRQ(ierr);
7922   }
7923   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7924   PetscFunctionReturn(0);
7925 }
7926 
7927 #undef __FUNCT__
7928 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7929 /* Set the constrained field indices on each point */
7930 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7931 {
7932   const PetscInt *points, *indices;
7933   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7934   PetscErrorCode  ierr;
7935 
7936   PetscFunctionBegin;
7937   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7938   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7939 
7940   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7941   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7942   if (!constraintIndices) {
7943     PetscInt *idx, i;
7944 
7945     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7946     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7947     for (i = 0; i < maxDof; ++i) idx[i] = i;
7948     for (p = 0; p < numPoints; ++p) {
7949       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7950     }
7951     ierr = PetscFree(idx);CHKERRQ(ierr);
7952   } else {
7953     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7954     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7955     for (p = 0; p < numPoints; ++p) {
7956       PetscInt fcdof;
7957 
7958       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7959       if (fcdof != numConstraints) SETERRQ4(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
7960       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7961     }
7962     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7963   }
7964   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7965   PetscFunctionReturn(0);
7966 }
7967 
7968 #undef __FUNCT__
7969 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7970 /* Set the constrained indices on each point and separate by fields */
7971 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7972 {
7973   PetscInt      *indices;
7974   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7975   PetscErrorCode ierr;
7976 
7977   PetscFunctionBegin;
7978   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7979   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7980   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7981   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7982   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7983   for (p = pStart; p < pEnd; ++p) {
7984     PetscInt cdof, d;
7985 
7986     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7987     if (cdof) {
7988       PetscInt numConst = 0, foff = 0;
7989 
7990       for (f = 0; f < numFields; ++f) {
7991         const PetscInt *fcind;
7992         PetscInt        fdof, fcdof;
7993 
7994         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7995         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7996         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7997         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7998         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
7999         foff     += fdof;
8000         numConst += fcdof;
8001       }
8002       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8003       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8004     }
8005   }
8006   ierr = PetscFree(indices);CHKERRQ(ierr);
8007   PetscFunctionReturn(0);
8008 }
8009 
8010 #undef __FUNCT__
8011 #define __FUNCT__ "DMPlexCreateSection"
8012 /*@C
8013   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8014 
8015   Not Collective
8016 
8017   Input Parameters:
8018 + dm        - The DMPlex object
8019 . dim       - The spatial dimension of the problem
8020 . numFields - The number of fields in the problem
8021 . numComp   - An array of size numFields that holds the number of components for each field
8022 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8023 . numBC     - The number of boundary conditions
8024 . bcField   - An array of size numBC giving the field number for each boundry condition
8025 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8026 
8027   Output Parameter:
8028 . section - The PetscSection object
8029 
8030   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
8031   nubmer of dof for field 0 on each edge.
8032 
8033   Level: developer
8034 
8035 .keywords: mesh, elements
8036 .seealso: DMPlexCreate(), PetscSectionCreate()
8037 @*/
8038 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8039 {
8040   PetscErrorCode ierr;
8041 
8042   PetscFunctionBegin;
8043   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8044   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8045   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8046   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8047   {
8048     PetscBool view = PETSC_FALSE;
8049 
8050     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8051     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8052   }
8053   PetscFunctionReturn(0);
8054 }
8055 
8056 #undef __FUNCT__
8057 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8058 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8059 {
8060   PetscSection   section;
8061   PetscErrorCode ierr;
8062 
8063   PetscFunctionBegin;
8064   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8065   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8066   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8067   PetscFunctionReturn(0);
8068 }
8069 
8070 #undef __FUNCT__
8071 #define __FUNCT__ "DMPlexGetCoordinateSection"
8072 /*@
8073   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8074 
8075   Not Collective
8076 
8077   Input Parameter:
8078 . dm - The DMPlex object
8079 
8080   Output Parameter:
8081 . section - The PetscSection object
8082 
8083   Level: intermediate
8084 
8085 .keywords: mesh, coordinates
8086 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8087 @*/
8088 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8089 {
8090   DM             cdm;
8091   PetscErrorCode ierr;
8092 
8093   PetscFunctionBegin;
8094   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8095   PetscValidPointer(section, 2);
8096   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8097   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8098   PetscFunctionReturn(0);
8099 }
8100 
8101 #undef __FUNCT__
8102 #define __FUNCT__ "DMPlexSetCoordinateSection"
8103 /*@
8104   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8105 
8106   Not Collective
8107 
8108   Input Parameters:
8109 + dm      - The DMPlex object
8110 - section - The PetscSection object
8111 
8112   Level: intermediate
8113 
8114 .keywords: mesh, coordinates
8115 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8116 @*/
8117 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8118 {
8119   DM             cdm;
8120   PetscErrorCode ierr;
8121 
8122   PetscFunctionBegin;
8123   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8124   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8125   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8126   PetscFunctionReturn(0);
8127 }
8128 
8129 #undef __FUNCT__
8130 #define __FUNCT__ "DMPlexGetConeSection"
8131 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8132 {
8133   DM_Plex *mesh = (DM_Plex*) dm->data;
8134 
8135   PetscFunctionBegin;
8136   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8137   if (section) *section = mesh->coneSection;
8138   PetscFunctionReturn(0);
8139 }
8140 
8141 #undef __FUNCT__
8142 #define __FUNCT__ "DMPlexGetCones"
8143 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8144 {
8145   DM_Plex *mesh = (DM_Plex*) dm->data;
8146 
8147   PetscFunctionBegin;
8148   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8149   if (cones) *cones = mesh->cones;
8150   PetscFunctionReturn(0);
8151 }
8152 
8153 #undef __FUNCT__
8154 #define __FUNCT__ "DMPlexGetConeOrientations"
8155 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8156 {
8157   DM_Plex *mesh = (DM_Plex*) dm->data;
8158 
8159   PetscFunctionBegin;
8160   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8161   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8162   PetscFunctionReturn(0);
8163 }
8164 
8165 #undef __FUNCT__
8166 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8167 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8168 {
8169   const PetscInt embedDim = 2;
8170   PetscReal      x        = PetscRealPart(point[0]);
8171   PetscReal      y        = PetscRealPart(point[1]);
8172   PetscReal      v0[2], J[4], invJ[4], detJ;
8173   PetscReal      xi, eta;
8174   PetscErrorCode ierr;
8175 
8176   PetscFunctionBegin;
8177   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8178   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8179   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8180 
8181   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
8182   else *cell = -1;
8183   PetscFunctionReturn(0);
8184 }
8185 
8186 #undef __FUNCT__
8187 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8188 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8189 {
8190   PetscSection       coordSection;
8191   Vec                coordsLocal;
8192   const PetscScalar *coords;
8193   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8194   PetscReal          x         = PetscRealPart(point[0]);
8195   PetscReal          y         = PetscRealPart(point[1]);
8196   PetscInt           crossings = 0, f;
8197   PetscErrorCode     ierr;
8198 
8199   PetscFunctionBegin;
8200   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8201   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8202   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8203   for (f = 0; f < 4; ++f) {
8204     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8205     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8206     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8207     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8208     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8209     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8210     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8211     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8212     if ((cond1 || cond2)  && above) ++crossings;
8213   }
8214   if (crossings % 2) *cell = c;
8215   else *cell = -1;
8216   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8217   PetscFunctionReturn(0);
8218 }
8219 
8220 #undef __FUNCT__
8221 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8222 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8223 {
8224   const PetscInt embedDim = 3;
8225   PetscReal      v0[3], J[9], invJ[9], detJ;
8226   PetscReal      x = PetscRealPart(point[0]);
8227   PetscReal      y = PetscRealPart(point[1]);
8228   PetscReal      z = PetscRealPart(point[2]);
8229   PetscReal      xi, eta, zeta;
8230   PetscErrorCode ierr;
8231 
8232   PetscFunctionBegin;
8233   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8234   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8235   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8236   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8237 
8238   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
8239   else *cell = -1;
8240   PetscFunctionReturn(0);
8241 }
8242 
8243 #undef __FUNCT__
8244 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8245 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8246 {
8247   PetscSection       coordSection;
8248   Vec                coordsLocal;
8249   const PetscScalar *coords;
8250   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8251                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8252   PetscBool          found = PETSC_TRUE;
8253   PetscInt           f;
8254   PetscErrorCode     ierr;
8255 
8256   PetscFunctionBegin;
8257   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8258   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8259   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8260   for (f = 0; f < 6; ++f) {
8261     /* Check the point is under plane */
8262     /*   Get face normal */
8263     PetscReal v_i[3];
8264     PetscReal v_j[3];
8265     PetscReal normal[3];
8266     PetscReal pp[3];
8267     PetscReal dot;
8268 
8269     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8270     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8271     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8272     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8273     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8274     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8275     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8276     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8277     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8278     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8279     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8280     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8281     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8282 
8283     /* Check that projected point is in face (2D location problem) */
8284     if (dot < 0.0) {
8285       found = PETSC_FALSE;
8286       break;
8287     }
8288   }
8289   if (found) *cell = c;
8290   else *cell = -1;
8291   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8292   PetscFunctionReturn(0);
8293 }
8294 
8295 #undef __FUNCT__
8296 #define __FUNCT__ "DMLocatePoints_Plex"
8297 /*
8298  Need to implement using the guess
8299 */
8300 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8301 {
8302   PetscInt       cell = -1 /*, guess = -1*/;
8303   PetscInt       bs, numPoints, p;
8304   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8305   PetscInt      *cells;
8306   PetscScalar   *a;
8307   PetscErrorCode ierr;
8308 
8309   PetscFunctionBegin;
8310   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8311   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8312   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8313   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8314   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8315   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8316   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8317   if (bs != dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
8318   numPoints /= bs;
8319   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8320   for (p = 0; p < numPoints; ++p) {
8321     const PetscScalar *point = &a[p*bs];
8322 
8323     switch (dim) {
8324     case 2:
8325       for (c = cStart; c < cEnd; ++c) {
8326         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8327         switch (coneSize) {
8328         case 3:
8329           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8330           break;
8331         case 4:
8332           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8333           break;
8334         default:
8335           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8336         }
8337         if (cell >= 0) break;
8338       }
8339       break;
8340     case 3:
8341       for (c = cStart; c < cEnd; ++c) {
8342         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8343         switch (coneSize) {
8344         case 4:
8345           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8346           break;
8347         case 8:
8348           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8349           break;
8350         default:
8351           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8352         }
8353         if (cell >= 0) break;
8354       }
8355       break;
8356     default:
8357       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8358     }
8359     cells[p] = cell;
8360   }
8361   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8362   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8363   PetscFunctionReturn(0);
8364 }
8365 
8366 /******************************** FEM Support **********************************/
8367 
8368 #undef __FUNCT__
8369 #define __FUNCT__ "DMPlexVecGetClosure"
8370 /*@C
8371   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8372 
8373   Not collective
8374 
8375   Input Parameters:
8376 + dm - The DM
8377 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8378 . v - The local vector
8379 - point - The sieve point in the DM
8380 
8381   Output Parameters:
8382 + csize - The number of values in the closure, or PETSC_NULL
8383 - values - The array of values, which is a borrowed array and should not be freed
8384 
8385   Level: intermediate
8386 
8387 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8388 @*/
8389 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8390 {
8391   PetscScalar   *array, *vArray;
8392   PetscInt      *points = PETSC_NULL;
8393   PetscInt       offsets[32];
8394   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8395   PetscErrorCode ierr;
8396 
8397   PetscFunctionBegin;
8398   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8399   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8400   if (!section) {
8401     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8402   }
8403   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8404   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8405   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8406   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8407   /* Compress out points not in the section */
8408   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8409   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8410     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8411       points[q*2]   = points[p];
8412       points[q*2+1] = points[p+1];
8413       ++q;
8414     }
8415   }
8416   numPoints = q;
8417   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8418     PetscInt dof, fdof;
8419 
8420     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8421     for (f = 0; f < numFields; ++f) {
8422       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8423       offsets[f+1] += fdof;
8424     }
8425     size += dof;
8426   }
8427   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8428   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8429   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8430   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8431   for (p = 0; p < numPoints*2; p += 2) {
8432     PetscInt     o = points[p+1];
8433     PetscInt     dof, off, d;
8434     PetscScalar *varr;
8435 
8436     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8437     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8438     varr = &vArray[off];
8439     if (numFields) {
8440       PetscInt fdof, foff, fcomp, f, c;
8441 
8442       for (f = 0, foff = 0; f < numFields; ++f) {
8443         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8444         if (o >= 0) {
8445           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8446             array[offsets[f]] = varr[foff+d];
8447           }
8448         } else {
8449           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8450           for (d = fdof/fcomp-1; d >= 0; --d) {
8451             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8452               array[offsets[f]] = varr[foff+d*fcomp+c];
8453             }
8454           }
8455         }
8456         foff += fdof;
8457       }
8458     } else {
8459       if (o >= 0) {
8460         for (d = 0; d < dof; ++d, ++offsets[0]) {
8461           array[offsets[0]] = varr[d];
8462         }
8463       } else {
8464         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8465           array[offsets[0]] = varr[d];
8466         }
8467       }
8468     }
8469   }
8470   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8471   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8472   if (csize) *csize = size;
8473   *values = array;
8474   PetscFunctionReturn(0);
8475 }
8476 
8477 #undef __FUNCT__
8478 #define __FUNCT__ "DMPlexVecRestoreClosure"
8479 /*@C
8480   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8481 
8482   Not collective
8483 
8484   Input Parameters:
8485 + dm - The DM
8486 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8487 . v - The local vector
8488 . point - The sieve point in the DM
8489 . csize - The number of values in the closure, or PETSC_NULL
8490 - values - The array of values, which is a borrowed array and should not be freed
8491 
8492   Level: intermediate
8493 
8494 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8495 @*/
8496 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8497 {
8498   PetscInt       size = 0;
8499   PetscErrorCode ierr;
8500 
8501   PetscFunctionBegin;
8502   /* Should work without recalculating size */
8503   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8504   PetscFunctionReturn(0);
8505 }
8506 
8507 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8508 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8509 
8510 #undef __FUNCT__
8511 #define __FUNCT__ "updatePoint_private"
8512 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8513 {
8514   PetscInt        cdof;   /* The number of constraints on this point */
8515   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8516   PetscScalar    *a;
8517   PetscInt        off, cind = 0, k;
8518   PetscErrorCode  ierr;
8519 
8520   PetscFunctionBegin;
8521   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8522   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8523   a    = &array[off];
8524   if (!cdof || setBC) {
8525     if (orientation >= 0) {
8526       for (k = 0; k < dof; ++k) {
8527         fuse(&a[k], values[k]);
8528       }
8529     } else {
8530       for (k = 0; k < dof; ++k) {
8531         fuse(&a[k], values[dof-k-1]);
8532       }
8533     }
8534   } else {
8535     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8536     if (orientation >= 0) {
8537       for (k = 0; k < dof; ++k) {
8538         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8539         fuse(&a[k], values[k]);
8540       }
8541     } else {
8542       for (k = 0; k < dof; ++k) {
8543         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8544         fuse(&a[k], values[dof-k-1]);
8545       }
8546     }
8547   }
8548   PetscFunctionReturn(0);
8549 }
8550 
8551 #undef __FUNCT__
8552 #define __FUNCT__ "updatePointFields_private"
8553 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8554 {
8555   PetscScalar   *a;
8556   PetscInt       numFields, off, foff, f;
8557   PetscErrorCode ierr;
8558 
8559   PetscFunctionBegin;
8560   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8561   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8562   a    = &array[off];
8563   for (f = 0, foff = 0; f < numFields; ++f) {
8564     PetscInt        fdof, fcomp, fcdof;
8565     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8566     PetscInt        cind = 0, k, c;
8567 
8568     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8569     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8570     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8571     if (!fcdof || setBC) {
8572       if (orientation >= 0) {
8573         for (k = 0; k < fdof; ++k) {
8574           fuse(&a[foff+k], values[foffs[f]+k]);
8575         }
8576       } else {
8577         for (k = fdof/fcomp-1; k >= 0; --k) {
8578           for (c = 0; c < fcomp; ++c) {
8579             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8580           }
8581         }
8582       }
8583     } else {
8584       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8585       if (orientation >= 0) {
8586         for (k = 0; k < fdof; ++k) {
8587           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
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             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8594             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8595           }
8596         }
8597       }
8598     }
8599     foff     += fdof;
8600     foffs[f] += fdof;
8601   }
8602   PetscFunctionReturn(0);
8603 }
8604 
8605 #undef __FUNCT__
8606 #define __FUNCT__ "DMPlexVecSetClosure"
8607 /*@C
8608   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8609 
8610   Not collective
8611 
8612   Input Parameters:
8613 + dm - The DM
8614 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8615 . v - The local vector
8616 . point - The sieve point in the DM
8617 . values - The array of values, which is a borrowed array and should not be freed
8618 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8619 
8620   Level: intermediate
8621 
8622 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8623 @*/
8624 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8625 {
8626   PetscScalar   *array;
8627   PetscInt      *points = PETSC_NULL;
8628   PetscInt       offsets[32];
8629   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8630   PetscErrorCode ierr;
8631 
8632   PetscFunctionBegin;
8633   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8634   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8635   if (!section) {
8636     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8637   }
8638   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8639   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8640   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8641   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8642   /* Compress out points not in the section */
8643   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8644   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8645     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8646       points[q*2]   = points[p];
8647       points[q*2+1] = points[p+1];
8648       ++q;
8649     }
8650   }
8651   numPoints = q;
8652   for (p = 0; p < numPoints*2; p += 2) {
8653     PetscInt fdof;
8654 
8655     for (f = 0; f < numFields; ++f) {
8656       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8657       offsets[f+1] += fdof;
8658     }
8659   }
8660   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8661   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8662   if (numFields) {
8663     switch (mode) {
8664     case INSERT_VALUES:
8665       for (p = 0; p < numPoints*2; p += 2) {
8666         PetscInt o = points[p+1];
8667         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8668       } break;
8669     case INSERT_ALL_VALUES:
8670       for (p = 0; p < numPoints*2; p += 2) {
8671         PetscInt o = points[p+1];
8672         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8673       } break;
8674     case ADD_VALUES:
8675       for (p = 0; p < numPoints*2; p += 2) {
8676         PetscInt o = points[p+1];
8677         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8678       } break;
8679     case ADD_ALL_VALUES:
8680       for (p = 0; p < numPoints*2; p += 2) {
8681         PetscInt o = points[p+1];
8682         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8683       } break;
8684     default:
8685       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8686     }
8687   } else {
8688     switch (mode) {
8689     case INSERT_VALUES:
8690       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8691         PetscInt o = points[p+1];
8692         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8693         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8694       } break;
8695     case INSERT_ALL_VALUES:
8696       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8697         PetscInt o = points[p+1];
8698         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8699         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8700       } break;
8701     case ADD_VALUES:
8702       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8703         PetscInt o = points[p+1];
8704         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8705         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8706       } break;
8707     case ADD_ALL_VALUES:
8708       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8709         PetscInt o = points[p+1];
8710         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8711         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8712       } break;
8713     default:
8714       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8715     }
8716   }
8717   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8718   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8719   PetscFunctionReturn(0);
8720 }
8721 
8722 #undef __FUNCT__
8723 #define __FUNCT__ "DMPlexPrintMatSetValues"
8724 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8725 {
8726   PetscMPIInt    rank;
8727   PetscInt       i, j;
8728   PetscErrorCode ierr;
8729 
8730   PetscFunctionBegin;
8731   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8732   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8733   for (i = 0; i < numIndices; i++) {
8734     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8735   }
8736   for (i = 0; i < numIndices; i++) {
8737     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8738     for (j = 0; j < numIndices; j++) {
8739 #if defined(PETSC_USE_COMPLEX)
8740       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8741 #else
8742       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8743 #endif
8744     }
8745     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8746   }
8747   PetscFunctionReturn(0);
8748 }
8749 
8750 #undef __FUNCT__
8751 #define __FUNCT__ "indicesPoint_private"
8752 /* . off - The global offset of this point */
8753 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8754 {
8755   PetscInt        cdof;   /* The number of constraints on this point */
8756   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8757   PetscInt        cind = 0, k;
8758   PetscErrorCode  ierr;
8759 
8760   PetscFunctionBegin;
8761   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8762   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8763   if (!cdof || setBC) {
8764     if (orientation >= 0) {
8765       for (k = 0; k < dof; ++k) indices[k] = off+k;
8766     } else {
8767       for (k = 0; k < dof; ++k) indices[dof-k-1] = off+k;
8768     }
8769   } else {
8770     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8771     if (orientation >= 0) {
8772       for (k = 0; k < dof; ++k) {
8773         if ((cind < cdof) && (k == cdofs[cind])) {
8774           /* Insert check for returning constrained indices */
8775           indices[k] = -(off+k+1);
8776           ++cind;
8777         } else {
8778           indices[k] = off+k-cind;
8779         }
8780       }
8781     } else {
8782       for (k = 0; k < dof; ++k) {
8783         if ((cind < cdof) && (k == cdofs[cind])) {
8784           /* Insert check for returning constrained indices */
8785           indices[dof-k-1] = -(off+k+1);
8786           ++cind;
8787         } else {
8788           indices[dof-k-1] = off+k-cind;
8789         }
8790       }
8791     }
8792   }
8793   PetscFunctionReturn(0);
8794 }
8795 
8796 #undef __FUNCT__
8797 #define __FUNCT__ "indicesPointFields_private"
8798 /* . off - The global offset of this point */
8799 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8800 {
8801   PetscInt       numFields, foff, f;
8802   PetscErrorCode ierr;
8803 
8804   PetscFunctionBegin;
8805   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8806   for (f = 0, foff = 0; f < numFields; ++f) {
8807     PetscInt        fdof, fcomp, cfdof;
8808     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8809     PetscInt        cind = 0, k, c;
8810 
8811     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8812     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8813     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8814     if (!cfdof || setBC) {
8815       if (orientation >= 0) {
8816         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8817       } else {
8818         for (k = fdof/fcomp-1; k >= 0; --k) {
8819           for (c = 0; c < fcomp; ++c) {
8820             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8821           }
8822         }
8823       }
8824     } else {
8825       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8826       if (orientation >= 0) {
8827         for (k = 0; k < fdof; ++k) {
8828           if ((cind < cfdof) && (k == fcdofs[cind])) {
8829             indices[foffs[f]+k] = -(off+foff+k+1);
8830             ++cind;
8831           } else {
8832             indices[foffs[f]+k] = off+foff+k-cind;
8833           }
8834         }
8835       } else {
8836         for (k = fdof/fcomp-1; k >= 0; --k) {
8837           for (c = 0; c < fcomp; ++c) {
8838             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8839               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8840               ++cind;
8841             } else {
8842               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8843             }
8844           }
8845         }
8846       }
8847     }
8848     foff     += fdof - cfdof;
8849     foffs[f] += fdof;
8850   }
8851   PetscFunctionReturn(0);
8852 }
8853 
8854 #undef __FUNCT__
8855 #define __FUNCT__ "DMPlexMatSetClosure"
8856 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8857 {
8858   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8859   PetscInt      *points = PETSC_NULL;
8860   PetscInt      *indices;
8861   PetscInt       offsets[32];
8862   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8863   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8864   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8865   PetscErrorCode ierr;
8866 
8867   PetscFunctionBegin;
8868   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8869   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8870   if (useDefault) {
8871     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8872   }
8873   if (useGlobalDefault) {
8874     if (useDefault) {
8875       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8876     } else {
8877       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8878     }
8879   }
8880   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8881   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8882   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8883   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8884   /* Compress out points not in the section */
8885   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8886   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8887     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8888       points[q*2]   = points[p];
8889       points[q*2+1] = points[p+1];
8890       ++q;
8891     }
8892   }
8893   numPoints = q;
8894   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8895     PetscInt fdof;
8896 
8897     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8898     for (f = 0; f < numFields; ++f) {
8899       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8900       offsets[f+1] += fdof;
8901     }
8902     numIndices += dof;
8903   }
8904   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8905 
8906   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8907   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8908   if (numFields) {
8909     for (p = 0; p < numPoints*2; p += 2) {
8910       PetscInt o = points[p+1];
8911       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8912       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8913     }
8914   } else {
8915     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8916       PetscInt o = points[p+1];
8917       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8918       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8919     }
8920   }
8921   if (useGlobalDefault && !useDefault) {
8922     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8923   }
8924   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8925   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8926   if (ierr) {
8927     PetscMPIInt    rank;
8928     PetscErrorCode ierr2;
8929 
8930     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8931     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8932     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8933     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8934     CHKERRQ(ierr);
8935   }
8936   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8937   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8938   PetscFunctionReturn(0);
8939 }
8940 
8941 #undef __FUNCT__
8942 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8943 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8944 {
8945   PetscSection       coordSection;
8946   Vec                coordinates;
8947   const PetscScalar *coords;
8948   const PetscInt     dim = 2;
8949   PetscInt           d, f;
8950   PetscErrorCode     ierr;
8951 
8952   PetscFunctionBegin;
8953   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8954   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8955   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8956   if (v0) {
8957     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8958   }
8959   if (J) {
8960     for (d = 0; d < dim; d++) {
8961       for (f = 0; f < dim; f++) {
8962         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8963       }
8964     }
8965     *detJ = J[0]*J[3] - J[1]*J[2];
8966 #if 0
8967     if (detJ < 0.0) {
8968       const PetscReal xLength = mesh->periodicity[0];
8969 
8970       if (xLength != 0.0) {
8971         PetscReal v0x = coords[0*dim+0];
8972 
8973         if (v0x == 0.0) v0x = v0[0] = xLength;
8974         for (f = 0; f < dim; f++) {
8975           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8976 
8977           J[0*dim+f] = 0.5*(px - v0x);
8978         }
8979       }
8980       detJ = J[0]*J[3] - J[1]*J[2];
8981     }
8982 #endif
8983     PetscLogFlops(8.0 + 3.0);
8984   }
8985   if (invJ) {
8986     const PetscReal invDet = 1.0/(*detJ);
8987 
8988     invJ[0] =  invDet*J[3];
8989     invJ[1] = -invDet*J[1];
8990     invJ[2] = -invDet*J[2];
8991     invJ[3] =  invDet*J[0];
8992     PetscLogFlops(5.0);
8993   }
8994   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8995   PetscFunctionReturn(0);
8996 }
8997 
8998 #undef __FUNCT__
8999 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9000 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9001 {
9002   PetscSection       coordSection;
9003   Vec                coordinates;
9004   const PetscScalar *coords;
9005   const PetscInt     dim = 2;
9006   PetscInt           d, f;
9007   PetscErrorCode     ierr;
9008 
9009   PetscFunctionBegin;
9010   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9011   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9012   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9013   if (v0) {
9014     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9015   }
9016   if (J) {
9017     for (d = 0; d < dim; d++) {
9018       for (f = 0; f < dim; f++) {
9019         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9020       }
9021     }
9022     *detJ = J[0]*J[3] - J[1]*J[2];
9023     PetscLogFlops(8.0 + 3.0);
9024   }
9025   if (invJ) {
9026     const PetscReal invDet = 1.0/(*detJ);
9027 
9028     invJ[0] =  invDet*J[3];
9029     invJ[1] = -invDet*J[1];
9030     invJ[2] = -invDet*J[2];
9031     invJ[3] =  invDet*J[0];
9032     PetscLogFlops(5.0);
9033   }
9034   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9035   PetscFunctionReturn(0);
9036 }
9037 
9038 #undef __FUNCT__
9039 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9040 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9041 {
9042   PetscSection       coordSection;
9043   Vec                coordinates;
9044   const PetscScalar *coords;
9045   const PetscInt     dim = 3;
9046   PetscInt           d, f;
9047   PetscErrorCode     ierr;
9048 
9049   PetscFunctionBegin;
9050   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9051   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9052   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9053   if (v0) {
9054     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9055   }
9056   if (J) {
9057     for (d = 0; d < dim; d++) {
9058       for (f = 0; f < dim; f++) {
9059         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9060       }
9061     }
9062     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9063     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9064              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9065              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9066     PetscLogFlops(18.0 + 12.0);
9067   }
9068   if (invJ) {
9069     const PetscReal invDet = 1.0/(*detJ);
9070 
9071     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9072     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9073     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9074     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9075     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9076     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9077     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9078     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9079     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9080     PetscLogFlops(37.0);
9081   }
9082   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9083   PetscFunctionReturn(0);
9084 }
9085 
9086 #undef __FUNCT__
9087 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9088 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9089 {
9090   PetscSection       coordSection;
9091   Vec                coordinates;
9092   const PetscScalar *coords;
9093   const PetscInt     dim = 3;
9094   PetscInt           d;
9095   PetscErrorCode     ierr;
9096 
9097   PetscFunctionBegin;
9098   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9099   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9100   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9101   if (v0) {
9102     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9103   }
9104   if (J) {
9105     for (d = 0; d < dim; d++) {
9106       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9107       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9108       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9109     }
9110     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9111              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9112              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9113     PetscLogFlops(18.0 + 12.0);
9114   }
9115   if (invJ) {
9116     const PetscReal invDet = -1.0/(*detJ);
9117 
9118     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9119     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9120     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9121     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9122     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9123     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9124     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9125     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9126     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9127     PetscLogFlops(37.0);
9128   }
9129   *detJ *= 8.0;
9130   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9131   PetscFunctionReturn(0);
9132 }
9133 
9134 #undef __FUNCT__
9135 #define __FUNCT__ "DMPlexComputeCellGeometry"
9136 /*@C
9137   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9138 
9139   Collective on DM
9140 
9141   Input Arguments:
9142 + dm   - the DM
9143 - cell - the cell
9144 
9145   Output Arguments:
9146 + v0   - the translation part of this affine transform
9147 . J    - the Jacobian of the transform to the reference element
9148 . invJ - the inverse of the Jacobian
9149 - detJ - the Jacobian determinant
9150 
9151   Level: advanced
9152 
9153 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9154 @*/
9155 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9156 {
9157   PetscInt       dim, coneSize;
9158   PetscErrorCode ierr;
9159 
9160   PetscFunctionBegin;
9161   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9162   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9163   switch (dim) {
9164   case 2:
9165     switch (coneSize) {
9166     case 3:
9167       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9168       break;
9169     case 4:
9170       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9171       break;
9172     default:
9173       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9174     }
9175     break;
9176   case 3:
9177     switch (coneSize) {
9178     case 4:
9179       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9180       break;
9181     case 8:
9182       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9183       break;
9184     default:
9185       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9186     }
9187     break;
9188   default:
9189     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9190   }
9191   PetscFunctionReturn(0);
9192 }
9193 
9194 #undef __FUNCT__
9195 #define __FUNCT__ "DMPlexGetFaceOrientation"
9196 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9197 {
9198   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9199   PetscBool      posOrient = PETSC_FALSE;
9200   const PetscInt debug     = 0;
9201   PetscInt       cellDim, faceSize, f;
9202   PetscErrorCode ierr;
9203 
9204   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9205   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9206 
9207   if (cellDim == numCorners-1) {
9208     /* Simplices */
9209     faceSize  = numCorners-1;
9210     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9211   } else if (cellDim == 1 && numCorners == 3) {
9212     /* Quadratic line */
9213     faceSize  = 1;
9214     posOrient = PETSC_TRUE;
9215   } else if (cellDim == 2 && numCorners == 4) {
9216     /* Quads */
9217     faceSize = 2;
9218     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9219       posOrient = PETSC_TRUE;
9220     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9221       posOrient = PETSC_TRUE;
9222     } else {
9223       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9224         posOrient = PETSC_FALSE;
9225       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9226     }
9227   } else if (cellDim == 2 && numCorners == 6) {
9228     /* Quadratic triangle (I hate this) */
9229     /* Edges are determined by the first 2 vertices (corners of edges) */
9230     const PetscInt faceSizeTri = 3;
9231     PetscInt       sortedIndices[3], i, iFace;
9232     PetscBool      found                    = PETSC_FALSE;
9233     PetscInt       faceVerticesTriSorted[9] = {
9234       0, 3,  4, /* bottom */
9235       1, 4,  5, /* right */
9236       2, 3,  5, /* left */
9237     };
9238     PetscInt       faceVerticesTri[9] = {
9239       0, 3,  4, /* bottom */
9240       1, 4,  5, /* right */
9241       2, 5,  3, /* left */
9242     };
9243 
9244     faceSize = faceSizeTri;
9245     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9246     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9247     for (iFace = 0; iFace < 3; ++iFace) {
9248       const PetscInt ii = iFace*faceSizeTri;
9249       PetscInt       fVertex, cVertex;
9250 
9251       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9252           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9253         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9254           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9255             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9256               faceVertices[fVertex] = origVertices[cVertex];
9257               break;
9258             }
9259           }
9260         }
9261         found = PETSC_TRUE;
9262         break;
9263       }
9264     }
9265     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9266     if (posOriented) *posOriented = PETSC_TRUE;
9267     PetscFunctionReturn(0);
9268   } else if (cellDim == 2 && numCorners == 9) {
9269     /* Quadratic quad (I hate this) */
9270     /* Edges are determined by the first 2 vertices (corners of edges) */
9271     const PetscInt faceSizeQuad = 3;
9272     PetscInt       sortedIndices[3], i, iFace;
9273     PetscBool      found                      = PETSC_FALSE;
9274     PetscInt       faceVerticesQuadSorted[12] = {
9275       0, 1,  4, /* bottom */
9276       1, 2,  5, /* right */
9277       2, 3,  6, /* top */
9278       0, 3,  7, /* left */
9279     };
9280     PetscInt       faceVerticesQuad[12] = {
9281       0, 1,  4, /* bottom */
9282       1, 2,  5, /* right */
9283       2, 3,  6, /* top */
9284       3, 0,  7, /* left */
9285     };
9286 
9287     faceSize = faceSizeQuad;
9288     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9289     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9290     for (iFace = 0; iFace < 4; ++iFace) {
9291       const PetscInt ii = iFace*faceSizeQuad;
9292       PetscInt       fVertex, cVertex;
9293 
9294       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9295           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9296         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9297           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9298             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9299               faceVertices[fVertex] = origVertices[cVertex];
9300               break;
9301             }
9302           }
9303         }
9304         found = PETSC_TRUE;
9305         break;
9306       }
9307     }
9308     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9309     if (posOriented) *posOriented = PETSC_TRUE;
9310     PetscFunctionReturn(0);
9311   } else if (cellDim == 3 && numCorners == 8) {
9312     /* Hexes
9313        A hex is two oriented quads with the normal of the first
9314        pointing up at the second.
9315 
9316           7---6
9317          /|  /|
9318         4---5 |
9319         | 3-|-2
9320         |/  |/
9321         0---1
9322 
9323         Faces are determined by the first 4 vertices (corners of faces) */
9324     const PetscInt faceSizeHex = 4;
9325     PetscInt       sortedIndices[4], i, iFace;
9326     PetscBool      found                     = PETSC_FALSE;
9327     PetscInt       faceVerticesHexSorted[24] = {
9328       0, 1, 2, 3,  /* bottom */
9329       4, 5, 6, 7,  /* top */
9330       0, 1, 4, 5,  /* front */
9331       1, 2, 5, 6,  /* right */
9332       2, 3, 6, 7,  /* back */
9333       0, 3, 4, 7,  /* left */
9334     };
9335     PetscInt       faceVerticesHex[24] = {
9336       3, 2, 1, 0,  /* bottom */
9337       4, 5, 6, 7,  /* top */
9338       0, 1, 5, 4,  /* front */
9339       1, 2, 6, 5,  /* right */
9340       2, 3, 7, 6,  /* back */
9341       3, 0, 4, 7,  /* left */
9342     };
9343 
9344     faceSize = faceSizeHex;
9345     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9346     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9347     for (iFace = 0; iFace < 6; ++iFace) {
9348       const PetscInt ii = iFace*faceSizeHex;
9349       PetscInt       fVertex, cVertex;
9350 
9351       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9352           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9353           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9354           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9355         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9356           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9357             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9358               faceVertices[fVertex] = origVertices[cVertex];
9359               break;
9360             }
9361           }
9362         }
9363         found = PETSC_TRUE;
9364         break;
9365       }
9366     }
9367     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9368     if (posOriented) *posOriented = PETSC_TRUE;
9369     PetscFunctionReturn(0);
9370   } else if (cellDim == 3 && numCorners == 10) {
9371     /* Quadratic tet */
9372     /* Faces are determined by the first 3 vertices (corners of faces) */
9373     const PetscInt faceSizeTet = 6;
9374     PetscInt       sortedIndices[6], i, iFace;
9375     PetscBool      found                     = PETSC_FALSE;
9376     PetscInt       faceVerticesTetSorted[24] = {
9377       0, 1, 2,  6, 7, 8, /* bottom */
9378       0, 3, 4,  6, 7, 9,  /* front */
9379       1, 4, 5,  7, 8, 9,  /* right */
9380       2, 3, 5,  6, 8, 9,  /* left */
9381     };
9382     PetscInt       faceVerticesTet[24] = {
9383       0, 1, 2,  6, 7, 8, /* bottom */
9384       0, 4, 3,  6, 7, 9,  /* front */
9385       1, 5, 4,  7, 8, 9,  /* right */
9386       2, 3, 5,  8, 6, 9,  /* left */
9387     };
9388 
9389     faceSize = faceSizeTet;
9390     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9391     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9392     for (iFace=0; iFace < 4; ++iFace) {
9393       const PetscInt ii = iFace*faceSizeTet;
9394       PetscInt       fVertex, cVertex;
9395 
9396       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9397           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9398           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9399           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9400         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9401           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9402             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9403               faceVertices[fVertex] = origVertices[cVertex];
9404               break;
9405             }
9406           }
9407         }
9408         found = PETSC_TRUE;
9409         break;
9410       }
9411     }
9412     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9413     if (posOriented) *posOriented = PETSC_TRUE;
9414     PetscFunctionReturn(0);
9415   } else if (cellDim == 3 && numCorners == 27) {
9416     /* Quadratic hexes (I hate this)
9417        A hex is two oriented quads with the normal of the first
9418        pointing up at the second.
9419 
9420          7---6
9421         /|  /|
9422        4---5 |
9423        | 3-|-2
9424        |/  |/
9425        0---1
9426 
9427        Faces are determined by the first 4 vertices (corners of faces) */
9428     const PetscInt faceSizeQuadHex = 9;
9429     PetscInt       sortedIndices[9], i, iFace;
9430     PetscBool      found                         = PETSC_FALSE;
9431     PetscInt       faceVerticesQuadHexSorted[54] = {
9432       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9433       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9434       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9435       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9436       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9437       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9438     };
9439     PetscInt       faceVerticesQuadHex[54] = {
9440       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9441       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9442       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9443       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9444       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9445       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9446     };
9447 
9448     faceSize = faceSizeQuadHex;
9449     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9450     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9451     for (iFace = 0; iFace < 6; ++iFace) {
9452       const PetscInt ii = iFace*faceSizeQuadHex;
9453       PetscInt       fVertex, cVertex;
9454 
9455       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9456           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9457           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9458           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9459         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9460           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9461             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9462               faceVertices[fVertex] = origVertices[cVertex];
9463               break;
9464             }
9465           }
9466         }
9467         found = PETSC_TRUE;
9468         break;
9469       }
9470     }
9471     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9472     if (posOriented) *posOriented = PETSC_TRUE;
9473     PetscFunctionReturn(0);
9474   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9475   if (!posOrient) {
9476     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9477     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize-1 - f];
9478   } else {
9479     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9480     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f];
9481   }
9482   if (posOriented) *posOriented = posOrient;
9483   PetscFunctionReturn(0);
9484 }
9485 
9486 #undef __FUNCT__
9487 #define __FUNCT__ "DMPlexGetOrientedFace"
9488 /*
9489     Given a cell and a face, as a set of vertices,
9490       return the oriented face, as a set of vertices, in faceVertices
9491     The orientation is such that the face normal points out of the cell
9492 */
9493 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9494 {
9495   const PetscInt *cone = PETSC_NULL;
9496   PetscInt        coneSize, v, f, v2;
9497   PetscInt        oppositeVertex = -1;
9498   PetscErrorCode  ierr;
9499 
9500   PetscFunctionBegin;
9501   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9502   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9503   for (v = 0, v2 = 0; v < coneSize; ++v) {
9504     PetscBool found = PETSC_FALSE;
9505 
9506     for (f = 0; f < faceSize; ++f) {
9507       if (face[f] == cone[v]) {
9508         found = PETSC_TRUE; break;
9509       }
9510     }
9511     if (found) {
9512       indices[v2]      = v;
9513       origVertices[v2] = cone[v];
9514       ++v2;
9515     } else {
9516       oppositeVertex = v;
9517     }
9518   }
9519   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9520   PetscFunctionReturn(0);
9521 }
9522 
9523 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9524 {
9525   switch (i) {
9526   case 0:
9527     switch (j) {
9528     case 0: return 0;
9529     case 1:
9530       switch (k) {
9531       case 0: return 0;
9532       case 1: return 0;
9533       case 2: return 1;
9534       }
9535     case 2:
9536       switch (k) {
9537       case 0: return 0;
9538       case 1: return -1;
9539       case 2: return 0;
9540       }
9541     }
9542   case 1:
9543     switch (j) {
9544     case 0:
9545       switch (k) {
9546       case 0: return 0;
9547       case 1: return 0;
9548       case 2: return -1;
9549       }
9550     case 1: return 0;
9551     case 2:
9552       switch (k) {
9553       case 0: return 1;
9554       case 1: return 0;
9555       case 2: return 0;
9556       }
9557     }
9558   case 2:
9559     switch (j) {
9560     case 0:
9561       switch (k) {
9562       case 0: return 0;
9563       case 1: return 1;
9564       case 2: return 0;
9565       }
9566     case 1:
9567       switch (k) {
9568       case 0: return -1;
9569       case 1: return 0;
9570       case 2: return 0;
9571       }
9572     case 2: return 0;
9573     }
9574   }
9575   return 0;
9576 }
9577 
9578 #undef __FUNCT__
9579 #define __FUNCT__ "DMPlexCreateRigidBody"
9580 /*@C
9581   DMPlexCreateRigidBody - create rigid body modes from coordinates
9582 
9583   Collective on DM
9584 
9585   Input Arguments:
9586 + dm - the DM
9587 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9588 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9589 
9590   Output Argument:
9591 . sp - the null space
9592 
9593   Note: This is necessary to take account of Dirichlet conditions on the displacements
9594 
9595   Level: advanced
9596 
9597 .seealso: MatNullSpaceCreate()
9598 @*/
9599 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9600 {
9601   MPI_Comm       comm = ((PetscObject) dm)->comm;
9602   Vec            coordinates, localMode, mode[6];
9603   PetscSection   coordSection;
9604   PetscScalar   *coords;
9605   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9606   PetscErrorCode ierr;
9607 
9608   PetscFunctionBegin;
9609   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9610   if (dim == 1) {
9611     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9612     PetscFunctionReturn(0);
9613   }
9614   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9615   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9616   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9617   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9618   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9619   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9620   m    = (dim*(dim+1))/2;
9621   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9622   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9623   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9624   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9625   /* Assume P1 */
9626   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9627   for (d = 0; d < dim; ++d) {
9628     PetscScalar values[3] = {0.0, 0.0, 0.0};
9629 
9630     values[d] = 1.0;
9631     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
9632     for (v = vStart; v < vEnd; ++v) {
9633       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9634     }
9635     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9636     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9637   }
9638   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9639   for (d = dim; d < dim*(dim+1)/2; ++d) {
9640     PetscInt i, j, k = dim > 2 ? d - dim : d;
9641 
9642     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9643     for (v = vStart; v < vEnd; ++v) {
9644       PetscScalar values[3] = {0.0, 0.0, 0.0};
9645       PetscInt    off;
9646 
9647       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9648       for (i = 0; i < dim; ++i) {
9649         for (j = 0; j < dim; ++j) {
9650           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9651         }
9652       }
9653       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9654     }
9655     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9656     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9657   }
9658   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9659   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9660   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9661   /* Orthonormalize system */
9662   for (i = dim; i < m; ++i) {
9663     PetscScalar dots[6];
9664 
9665     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9666     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9667     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9668     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9669   }
9670   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9671   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9672   PetscFunctionReturn(0);
9673 }
9674 
9675 #undef __FUNCT__
9676 #define __FUNCT__ "DMPlexGetHybridBounds"
9677 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9678 {
9679   DM_Plex       *mesh = (DM_Plex*) dm->data;
9680   PetscInt       dim;
9681   PetscErrorCode ierr;
9682 
9683   PetscFunctionBegin;
9684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9685   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9686   if (cMax) *cMax = mesh->hybridPointMax[dim];
9687   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9688   if (eMax) *eMax = mesh->hybridPointMax[1];
9689   if (vMax) *vMax = mesh->hybridPointMax[0];
9690   PetscFunctionReturn(0);
9691 }
9692 
9693 #undef __FUNCT__
9694 #define __FUNCT__ "DMPlexSetHybridBounds"
9695 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9696 {
9697   DM_Plex       *mesh = (DM_Plex*) dm->data;
9698   PetscInt       dim;
9699   PetscErrorCode ierr;
9700 
9701   PetscFunctionBegin;
9702   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9703   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9704   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9705   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9706   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9707   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9708   PetscFunctionReturn(0);
9709 }
9710 
9711 #undef __FUNCT__
9712 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9713 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9714 {
9715   DM_Plex *mesh = (DM_Plex*) dm->data;
9716 
9717   PetscFunctionBegin;
9718   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9719   PetscValidPointer(cellHeight, 2);
9720   *cellHeight = mesh->vtkCellHeight;
9721   PetscFunctionReturn(0);
9722 }
9723 
9724 #undef __FUNCT__
9725 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9726 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9727 {
9728   DM_Plex *mesh = (DM_Plex*) dm->data;
9729 
9730   PetscFunctionBegin;
9731   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9732   mesh->vtkCellHeight = cellHeight;
9733   PetscFunctionReturn(0);
9734 }
9735 
9736 #undef __FUNCT__
9737 #define __FUNCT__ "DMPlexInsertFace_Private"
9738 /*
9739   DMPlexInsertFace_Private - Puts a face into the mesh
9740 
9741   Not collective
9742 
9743   Input Parameters:
9744   + dm              - The DMPlex
9745   . numFaceVertex   - The number of vertices in the face
9746   . faceVertices    - The vertices in the face for dm
9747   . subfaceVertices - The vertices in the face for subdm
9748   . numCorners      - The number of vertices in the cell
9749   . cell            - A cell in dm containing the face
9750   . subcell         - A cell in subdm containing the face
9751   . firstFace       - First face in the mesh
9752   - newFacePoint    - Next face in the mesh
9753 
9754   Output Parameters:
9755   . newFacePoint - Contains next face point number on input, updated on output
9756 
9757   Level: developer
9758 */
9759 PetscErrorCode DMPlexInsertFace_Private(DM dm, DM subdm, PetscInt numFaceVertices, const PetscInt faceVertices[], const PetscInt subfaceVertices[], PetscInt numCorners, PetscInt cell, PetscInt subcell, PetscInt firstFace, PetscInt *newFacePoint)
9760 {
9761   MPI_Comm        comm    = ((PetscObject) dm)->comm;
9762   DM_Plex        *submesh = (DM_Plex*) subdm->data;
9763   const PetscInt *faces;
9764   PetscInt        numFaces, coneSize;
9765   PetscErrorCode  ierr;
9766 
9767   PetscFunctionBegin;
9768   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9769   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9770 #if 0
9771   /* Cannot use this because support() has not been constructed yet */
9772   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9773 #else
9774   {
9775     PetscInt f;
9776 
9777     numFaces = 0;
9778     ierr     = DMGetWorkArray(subdm, 1, PETSC_INT, (void**) &faces);CHKERRQ(ierr);
9779     for (f = firstFace; f < *newFacePoint; ++f) {
9780       PetscInt dof, off, d;
9781 
9782       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9783       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9784       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9785       for (d = 0; d < dof; ++d) {
9786         const PetscInt p = submesh->cones[off+d];
9787         PetscInt       v;
9788 
9789         for (v = 0; v < numFaceVertices; ++v) {
9790           if (subfaceVertices[v] == p) break;
9791         }
9792         if (v == numFaceVertices) break;
9793       }
9794       if (d == dof) {
9795         numFaces               = 1;
9796         ((PetscInt*) faces)[0] = f;
9797       }
9798     }
9799   }
9800 #endif
9801   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
9802   else if (numFaces == 1) {
9803     /* Add the other cell neighbor for this face */
9804     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
9805   } else {
9806     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
9807     PetscBool posOriented;
9808 
9809     ierr                = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9810     origVertices        = &orientedVertices[numFaceVertices];
9811     indices             = &orientedVertices[numFaceVertices*2];
9812     orientedSubVertices = &orientedVertices[numFaceVertices*3];
9813     ierr                = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
9814     /* TODO: I know that routine should return a permutation, not the indices */
9815     for (v = 0; v < numFaceVertices; ++v) {
9816       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
9817       for (ov = 0; ov < numFaceVertices; ++ov) {
9818         if (orientedVertices[ov] == vertex) {
9819           orientedSubVertices[ov] = subvertex;
9820           break;
9821         }
9822       }
9823       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
9824     }
9825     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
9826     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
9827     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9828     ++(*newFacePoint);
9829   }
9830   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9831   PetscFunctionReturn(0);
9832 }
9833 
9834 #undef __FUNCT__
9835 #define __FUNCT__ "DMPlexCreateSubmesh_Uninterpolated"
9836 static PetscErrorCode DMPlexCreateSubmesh_Uninterpolated(DM dm, const char label[], const char surfaceLabel[], DM subdm)
9837 {
9838   MPI_Comm        comm = ((PetscObject) dm)->comm;
9839   PetscBool       boundaryFaces = PETSC_FALSE;
9840   PetscSection    coordSection, subCoordSection;
9841   Vec             coordinates, subCoordinates;
9842   PetscScalar    *coords, *subCoords;
9843   IS              labelIS, subpointMap;
9844   const PetscInt *subVertices;
9845   PetscInt       *subVerticesActive, *tmpPoints;
9846   PetscInt       *subCells = PETSC_NULL;
9847   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
9848   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
9849   PetscInt        dim;  /* Right now, do not specify dimension */
9850   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
9851   PetscErrorCode  ierr;
9852 
9853   PetscFunctionBegin;
9854   if (surfaceLabel) SETERRQ(comm, PETSC_ERR_SUP, "Yell at me to do this");
9855   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9856   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9857   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9858   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
9859   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
9860   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9861   if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9862   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9863   subface = &face[maxConeSize];
9864   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
9865   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
9866   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
9867   maxSubCells = numSubVertices;
9868   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
9869   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
9870   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
9871   for (v = 0; v < numSubVertices; ++v) {
9872     const PetscInt vertex = subVertices[v];
9873     PetscInt      *star   = PETSC_NULL;
9874     PetscInt       starSize, numCells = 0;
9875 
9876     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9877     for (p = 0; p < starSize*2; p += 2) {
9878       const PetscInt point = star[p];
9879       if ((point >= cStart) && (point < cEnd)) star[numCells++] = point;
9880     }
9881     numOldSubCells = numSubCells;
9882     for (c = 0; c < numCells; ++c) {
9883       const PetscInt cell    = star[c];
9884       PetscInt      *closure = PETSC_NULL;
9885       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9886       PetscInt       cellLoc;
9887 
9888       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9889       if (cellLoc >= 0) continue;
9890       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9891       for (p = 0; p < closureSize*2; p += 2) {
9892         const PetscInt point = closure[p];
9893         if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
9894       }
9895       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9896       for (corner = 0; corner < numCorners; ++corner) {
9897         const PetscInt cellVertex = closure[corner];
9898         PetscInt       subVertex;
9899 
9900         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
9901         if (subVertex >= 0) { /* contains submesh vertex */
9902           for (i = 0; i < faceSize; ++i) {
9903             if (cellVertex == face[i]) break;
9904           }
9905           if (i == faceSize) {
9906             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
9907             face[faceSize]    = cellVertex;
9908             subface[faceSize] = subVertex;
9909             ++faceSize;
9910           }
9911         }
9912       }
9913       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9914       if (faceSize >= nFV) {
9915         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9916         if (numSubCells >= maxSubCells) {
9917           PetscInt *tmpCells;
9918           maxSubCells *= 2;
9919           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
9920           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
9921           ierr = PetscFree(subCells);CHKERRQ(ierr);
9922 
9923           subCells = tmpCells;
9924         }
9925         /* TOOD: Maybe overestimate then squeeze out empty faces */
9926         if (faceSize > nFV) {
9927           /* TODO: This is tricky. Maybe just add all faces */
9928           numSubFaces++;
9929         } else {
9930           numSubFaces++;
9931         }
9932         for (f = 0; f < faceSize; ++f) subVerticesActive[subface[f]] = 1;
9933         subCells[numSubCells++] = cell;
9934       }
9935     }
9936     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9937     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
9938   }
9939   /* Pick out active subvertices */
9940   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
9941     if (subVerticesActive[v]) {
9942       subVerticesActive[numSubVerticesActive++] = subVertices[v];
9943     }
9944   }
9945   ierr = DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
9946   /* Set cone sizes */
9947   firstSubVertex = numSubCells;
9948   firstSubFace   = numSubCells+numSubVerticesActive;
9949   newFacePoint   = firstSubFace;
9950   for (c = 0; c < numSubCells; ++c) {
9951     ierr = DMPlexSetConeSize(subdm, c, 1);CHKERRQ(ierr);
9952   }
9953   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
9954     ierr = DMPlexSetConeSize(subdm, f, nFV);CHKERRQ(ierr);
9955   }
9956   ierr = DMSetUp(subdm);CHKERRQ(ierr);
9957   /* Create face cones */
9958   for (c = 0; c < numSubCells; ++c) {
9959     const PetscInt cell    = subCells[c];
9960     PetscInt      *closure = PETSC_NULL;
9961     PetscInt       closureSize, numCorners = 0, faceSize = 0;
9962 
9963     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9964     for (p = 0; p < closureSize*2; p += 2) {
9965       const PetscInt point = closure[p];
9966       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
9967     }
9968     for (corner = 0; corner < numCorners; ++corner) {
9969       const PetscInt cellVertex = closure[corner];
9970       PetscInt       subVertex;
9971 
9972       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
9973       if (subVertex >= 0) { /* contains submesh vertex */
9974         for (i = 0; i < faceSize; ++i) {
9975           if (cellVertex == face[i]) break;
9976         }
9977         if (i == faceSize) {
9978           face[faceSize]    = cellVertex;
9979           subface[faceSize] = numSubCells+subVertex;
9980           ++faceSize;
9981         }
9982       }
9983     }
9984     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9985     if (faceSize >= nFV) {
9986       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9987       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
9988       /*   We have to take all the faces, and discard those in the interior */
9989       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
9990 #if 0
9991       /* This object just calls insert on each face that comes from subsets() */
9992       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
9993       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
9994       PointArray                          faceVec(face->begin(), face->end());
9995 
9996       subsets(faceVec, nFV, inserter);
9997 #endif
9998       ierr = DMPlexInsertFace_Private(dm, subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
9999     }
10000   }
10001   ierr = DMPlexSymmetrize(subdm);CHKERRQ(ierr);
10002   ierr = DMPlexStratify(subdm);CHKERRQ(ierr);
10003   /* Build coordinates */
10004   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10005   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10006   ierr = DMPlexGetCoordinateSection(subdm, &subCoordSection);CHKERRQ(ierr);
10007   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10008   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10009     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10010   }
10011   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10012   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10013   ierr = VecCreate(comm, &subCoordinates);CHKERRQ(ierr);
10014   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10015   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10016   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10017   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10018   for (v = 0; v < numSubVerticesActive; ++v) {
10019     const PetscInt vertex    = subVerticesActive[v];
10020     const PetscInt subVertex = firstSubVertex+v;
10021     PetscInt       dof, off, sdof, soff;
10022 
10023     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10024     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10025     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10026     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10027     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10028     for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
10029   }
10030   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10031   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10032   ierr = DMSetCoordinatesLocal(subdm, subCoordinates);CHKERRQ(ierr);
10033   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10034 
10035   ierr = DMPlexSetVTKCellHeight(subdm, 1);CHKERRQ(ierr);
10036   /* Create map from submesh points to original mesh points */
10037   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10038   for (c = 0; c < numSubCells; ++c) tmpPoints[c] = subCells[c];
10039   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) tmpPoints[v] = subVerticesActive[v-numSubCells];
10040   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &subpointMap);CHKERRQ(ierr);
10041   ierr = DMPlexSetSubpointMap(subdm, subpointMap);CHKERRQ(ierr);
10042   ierr = ISDestroy(&subpointMap);CHKERRQ(ierr);
10043 
10044   ierr = PetscFree(subCells);CHKERRQ(ierr);
10045   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10046   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10047   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10048   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10049   PetscFunctionReturn(0);
10050 }
10051 
10052 #undef __FUNCT__
10053 #define __FUNCT__ "DMPlexCreateSubmesh_Interpolated"
10054 static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, const char vertexLabel[], const char surfaceLabel[], DM subdm)
10055 {
10056   MPI_Comm        comm = ((PetscObject) dm)->comm;
10057   const char     *name = surfaceLabel ? surfaceLabel : "submesh_label";
10058   DMLabel         slabel;
10059   IS              subvertexIS, subedgeIS, subfaceIS, subcellIS, subpointMap;
10060   const PetscInt *subVertices, *subEdges, *subFaces, *subCells;
10061   PetscInt       *coneNew;
10062   PetscInt        dim, numSubVerticesInitial, numSubVertices, firstSubVertex, v, numSubEdges = 0, firstSubEdge, e, numSubFaces = 0, firstSubFace, f, numSubCells;
10063   PetscInt        vStart, vEnd, fStart, fEnd;
10064   PetscErrorCode  ierr;
10065 
10066   PetscFunctionBegin;
10067   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10068   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10069   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
10070   ierr = DMPlexCreateLabel(subdm, name);CHKERRQ(ierr);
10071   ierr = DMPlexGetLabel(subdm, name, &slabel);CHKERRQ(ierr);
10072   ierr = DMPlexGetStratumIS(dm, vertexLabel, 1, &subvertexIS);CHKERRQ(ierr);
10073   ierr = ISGetSize(subvertexIS, &numSubVerticesInitial);CHKERRQ(ierr);
10074   ierr = ISGetIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10075   for (v = 0; v < numSubVerticesInitial; ++v) {
10076     const PetscInt vertex = subVertices[v];
10077     PetscInt *star = PETSC_NULL;
10078     PetscInt  starSize, s, numFaces = 0, f;
10079 
10080     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10081     for (s = 0; s < starSize*2; s += 2) {
10082       const PetscInt point = star[s];
10083       if ((point >= fStart) && (point < fEnd)) {
10084         star[numFaces++] = point;
10085       }
10086     }
10087     for (f = 0; f < numFaces; ++f) {
10088       const PetscInt face    = star[f];
10089       PetscInt      *closure = PETSC_NULL;
10090       PetscInt       closureSize, c, numCorners = 0;
10091       PetscInt       faceLoc, corner;
10092 
10093       ierr = DMLabelGetValue(slabel, face, &faceLoc);CHKERRQ(ierr);
10094       if (faceLoc == dim-1) continue;
10095       if (faceLoc >= 0) SETERRQ2(comm, PETSC_ERR_PLIB, "Face %d has dimension %d in the surface label", face, faceLoc);
10096       ierr = DMPlexGetTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10097       for (c = 0; c < closureSize*2; c += 2) {
10098         const PetscInt point = closure[c];
10099         if ((point >= vStart) && (point < vEnd)) {
10100           closure[numCorners++] = point;
10101         }
10102       }
10103       for (corner = 0; corner < numCorners; ++corner) {
10104         const PetscInt cellVertex = closure[corner];
10105         PetscInt       vertexLoc;
10106 
10107         ierr = DMLabelGetValue(slabel, cellVertex, &vertexLoc);CHKERRQ(ierr);
10108         if (vertexLoc < 0) break;
10109       }
10110       ierr = DMPlexRestoreTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10111       if (corner == numCorners) {
10112         const PetscInt *support;
10113         PetscInt        supportSize;
10114 
10115         for (corner = 0; corner < numCorners; ++corner) {ierr = DMLabelSetValue(slabel, closure[corner], 0);CHKERRQ(ierr);}
10116         ierr = DMLabelSetValue(slabel, face, dim-1);CHKERRQ(ierr);
10117         ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
10118         ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
10119         for(s = 0; s < supportSize; ++s) {
10120           ierr = DMLabelSetValue(slabel, support[s], dim);CHKERRQ(ierr);
10121         }
10122         if (dim > 2) {
10123           const PetscInt *cone;
10124           PetscInt        coneSize;
10125 
10126           ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10127           ierr = DMPlexGetCone(dm, face, &cone);CHKERRQ(ierr);
10128           for(c = 0; c < coneSize; ++c) {
10129             ierr = DMLabelSetValue(slabel, cone[c], dim-2);CHKERRQ(ierr);
10130           }
10131         }
10132       }
10133     }
10134     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10135   }
10136   ierr = ISRestoreIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10137   ierr = ISDestroy(&subvertexIS);CHKERRQ(ierr);
10138   ierr = DMLabelGetStratumSize(slabel, dim,   &numSubCells);CHKERRQ(ierr);
10139   ierr = DMLabelGetStratumSize(slabel, 0,     &numSubVertices);CHKERRQ(ierr);
10140   if (dim > 1) {ierr = DMLabelGetStratumSize(slabel, dim-1, &numSubFaces);CHKERRQ(ierr);}
10141   if (dim > 2) {ierr = DMLabelGetStratumSize(slabel, 1,     &numSubEdges);CHKERRQ(ierr);}
10142   ierr = DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubEdges+numSubVertices);CHKERRQ(ierr);
10143   ierr = DMPlexSetVTKCellHeight(subdm, 1);CHKERRQ(ierr);
10144   /* Set cone sizes */
10145   firstSubVertex = numSubCells;
10146   firstSubFace   = firstSubVertex + numSubVertices;
10147   firstSubEdge   = firstSubFace   + numSubFaces;
10148   ierr = DMLabelGetStratumIS(slabel, dim,   &subcellIS);CHKERRQ(ierr);
10149   ierr = ISGetIndices(subcellIS, &subCells);CHKERRQ(ierr);
10150   ierr = DMLabelGetStratumIS(slabel, 0,     &subvertexIS);CHKERRQ(ierr);
10151   ierr = ISGetIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10152   if (dim > 1) {
10153     ierr = DMLabelGetStratumIS(slabel, dim-1, &subfaceIS);CHKERRQ(ierr);
10154     ierr = ISGetIndices(subfaceIS, &subFaces);CHKERRQ(ierr);
10155   }
10156   if (dim > 2) {
10157     ierr = DMLabelGetStratumIS(slabel, 1,     &subedgeIS);CHKERRQ(ierr);
10158     ierr = ISGetIndices(subedgeIS, &subEdges);CHKERRQ(ierr);
10159   }
10160   for (e = firstSubEdge; e < firstSubEdge+numSubEdges; ++e) {
10161     ierr = DMPlexSetConeSize(subdm, e, 2);CHKERRQ(ierr);
10162   }
10163   for (f = 0; f < numSubFaces; ++f) {
10164     const PetscInt  face    = subFaces[f];
10165     const PetscInt  subface = firstSubFace + f;
10166     const PetscInt *support;
10167     PetscInt        coneSize, supportSize, subcell, s;
10168 
10169     ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10170     ierr = DMPlexSetConeSize(subdm, subface, coneSize);CHKERRQ(ierr);
10171     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
10172     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
10173     for(s = 0; s < supportSize; ++s) {
10174       ierr = PetscFindInt(support[s], numSubCells, subCells, &subcell);CHKERRQ(ierr);
10175       if (subcell < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Subcell %d not found in surface label", support[s]);
10176       /* ierr = DMPlexAddConeSize(subdm, subcell, 1);CHKERRQ(ierr); */
10177     }
10178   }
10179   ierr = DMSetUp(subdm);CHKERRQ(ierr);
10180   /* Set cones */
10181   for (e = 0; e < numSubEdges; ++e) {
10182     const PetscInt  edge    = subEdges[e];
10183     const PetscInt  subedge = firstSubEdge + e;
10184     const PetscInt *cone;
10185     PetscInt        coneSize, c, coneNew[2], subv;
10186 
10187     ierr = DMPlexGetConeSize(subdm, e, &coneSize);CHKERRQ(ierr);
10188     if (coneSize != 2) SETERRQ3(comm, PETSC_ERR_ARG_OUTOFRANGE, "Edge %d matching subedge %d had cone size %d != 2", edge, subedge, coneSize);
10189     ierr = DMPlexGetCone(subdm, e, &cone);CHKERRQ(ierr);
10190     for(c = 0; c < coneSize; ++c) {
10191       ierr = PetscFindInt(cone[c], numSubVertices, subVertices, &subv);CHKERRQ(ierr);
10192       if (subv < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Vertex %d has no matching subvertex", cone[v]);
10193       coneNew[c] = firstSubVertex + subv;
10194     }
10195     ierr = DMPlexSetCone(subdm, e, coneNew);CHKERRQ(ierr);
10196   }
10197   for (f = 0; f < numSubFaces; ++f) {
10198     const PetscInt  face    = subFaces[f];
10199     const PetscInt  subface = firstSubFace + f;
10200     const PetscInt *cone, *support;
10201     PetscInt        coneSize, supportSize, subvertex, subcell, c, s;
10202 
10203     ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10204     ierr = DMPlexGetCone(dm, face, &cone);CHKERRQ(ierr);
10205     for(c = 0; c < coneSize; ++c) {
10206       ierr = PetscFindInt(cone[c], numSubVertices, subVertices, &subvertex);CHKERRQ(ierr);
10207       if (subvertex < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Vertex %d has no matching subvertex", cone[v]);
10208       coneNew[c] = firstSubVertex + subvertex;
10209     }
10210     ierr = DMPlexSetCone(subdm, subface, coneNew);CHKERRQ(ierr);
10211     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
10212     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
10213     for(s = 0; s < supportSize; ++s) {
10214       ierr = PetscFindInt(support[s], numSubCells, subCells, &subcell);CHKERRQ(ierr);
10215       if (subcell < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Subcell %d not found in surface label", support[s]);
10216       /* ierr = DMPlexAddCone(subdm, subcell, 1);CHKERRQ(ierr); */
10217     }
10218   }
10219   ierr = ISRestoreIndices(subcellIS, &subCells);CHKERRQ(ierr);
10220   ierr = ISDestroy(&subcellIS);CHKERRQ(ierr);
10221   ierr = ISRestoreIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10222   ierr = ISDestroy(&subvertexIS);CHKERRQ(ierr);
10223   if (dim > 1) {
10224     ierr = ISRestoreIndices(subfaceIS, &subFaces);CHKERRQ(ierr);
10225     ierr = ISDestroy(&subfaceIS);CHKERRQ(ierr);
10226   }
10227   if (dim > 2) {
10228     ierr = ISRestoreIndices(subedgeIS, &subEdges);CHKERRQ(ierr);
10229     ierr = ISDestroy(&subedgeIS);CHKERRQ(ierr);
10230   }
10231   ierr = DMPlexSymmetrize(subdm);CHKERRQ(ierr);
10232   ierr = DMPlexStratify(subdm);CHKERRQ(ierr);
10233   /* Build coordinates */
10234   {
10235     PetscSection    coordSection, subCoordSection;
10236     Vec             coordinates, subCoordinates;
10237     PetscScalar    *coords, *subCoords;
10238     PetscInt        coordSize;
10239 
10240     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10241     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10242     ierr = DMPlexGetCoordinateSection(subdm, &subCoordSection);CHKERRQ(ierr);
10243     ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVertices);CHKERRQ(ierr);
10244     for (v = 0; v < numSubVertices; ++v) {
10245       const PetscInt vertex    = subVertices[v];
10246       const PetscInt subVertex = firstSubVertex+v;
10247       PetscInt       dof;
10248 
10249       ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10250       ierr = PetscSectionSetDof(subCoordSection, subVertex, dof);CHKERRQ(ierr);
10251     }
10252     ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10253     ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10254     ierr = VecCreate(comm, &subCoordinates);CHKERRQ(ierr);
10255     ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10256     ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10257     ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10258     ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10259     for (v = 0; v < numSubVertices; ++v) {
10260       const PetscInt vertex    = subVertices[v];
10261       const PetscInt subVertex = firstSubVertex+v;
10262       PetscInt dof, off, sdof, soff, d;
10263 
10264       ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10265       ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10266       ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10267       ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10268       if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10269       for (d = 0; d < dof; ++d) {
10270         subCoords[soff+d] = coords[off+d];
10271       }
10272     }
10273     ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10274     ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10275     ierr = DMSetCoordinatesLocal(subdm, subCoordinates);CHKERRQ(ierr);
10276     ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10277   }
10278   /* TODO: Create map from submesh points to original mesh points */
10279   ierr = DMPlexSetSubpointMap(subdm, subpointMap);CHKERRQ(ierr);
10280   PetscFunctionReturn(0);
10281 }
10282 
10283 #undef __FUNCT__
10284 #define __FUNCT__ "DMPlexCreateSubmesh"
10285 /*
10286   DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label
10287 
10288   Input Parameters:
10289 + dm           - The original mesh
10290 . vertexLabel  - The DMLabel marking vertices contained in the surface
10291 - surfaceLabel - If not PETSC_NULL, create a new label with all the surface points labeled by dimension
10292 
10293   Output Parameter:
10294 . subdm - The surface mesh
10295 
10296   Level: developer
10297 
10298 .seealso: DMPlexGetLabel(), DMLabelSetValue()
10299 */
10300 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char vertexLabel[], const char surfaceLabel[], DM *subdm)
10301 {
10302   PetscInt       dim, depth;
10303   PetscErrorCode ierr;
10304 
10305   PetscFunctionBegin;
10306   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10307   PetscValidCharPointer(vertexLabel, 2);
10308   PetscValidPointer(subdm, 4);
10309   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10310   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10311   ierr = DMCreate(((PetscObject) dm)->comm, subdm);CHKERRQ(ierr);
10312   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
10313   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
10314   if (depth == dim) {
10315     ierr = DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, surfaceLabel, *subdm);CHKERRQ(ierr);
10316   } else {
10317     ierr = DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, surfaceLabel, *subdm);CHKERRQ(ierr);
10318   }
10319   PetscFunctionReturn(0);
10320 }
10321 
10322 #undef __FUNCT__
10323 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10324 /* We can easily have a form that takes an IS instead */
10325 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10326 {
10327   PetscSection   section, globalSection;
10328   PetscInt      *numbers, p;
10329   PetscErrorCode ierr;
10330 
10331   PetscFunctionBegin;
10332   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10333   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10334   for (p = pStart; p < pEnd; ++p) {
10335     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10336   }
10337   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10338   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10339   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10340   for (p = pStart; p < pEnd; ++p) {
10341     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10342   }
10343   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10344   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10345   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10346   PetscFunctionReturn(0);
10347 }
10348 
10349 #undef __FUNCT__
10350 #define __FUNCT__ "DMPlexGetCellNumbering"
10351 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10352 {
10353   DM_Plex       *mesh = (DM_Plex*) dm->data;
10354   PetscInt       cellHeight, cStart, cEnd, cMax;
10355   PetscErrorCode ierr;
10356 
10357   PetscFunctionBegin;
10358   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10359   if (!mesh->globalCellNumbers) {
10360     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10361     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10362     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10363     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
10364     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10365   }
10366   *globalCellNumbers = mesh->globalCellNumbers;
10367   PetscFunctionReturn(0);
10368 }
10369 
10370 #undef __FUNCT__
10371 #define __FUNCT__ "DMPlexGetVertexNumbering"
10372 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10373 {
10374   DM_Plex       *mesh = (DM_Plex*) dm->data;
10375   PetscInt       vStart, vEnd, vMax;
10376   PetscErrorCode ierr;
10377 
10378   PetscFunctionBegin;
10379   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10380   if (!mesh->globalVertexNumbers) {
10381     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10382     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10383     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
10384     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10385   }
10386   *globalVertexNumbers = mesh->globalVertexNumbers;
10387   PetscFunctionReturn(0);
10388 }
10389 
10390 #undef __FUNCT__
10391 #define __FUNCT__ "DMPlexGetSubpointMap"
10392 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10393 {
10394   DM_Plex *mesh = (DM_Plex*) dm->data;
10395 
10396   PetscFunctionBegin;
10397   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10398   PetscValidPointer(subpointMap, 2);
10399   *subpointMap = mesh->subpointMap;
10400   PetscFunctionReturn(0);
10401 }
10402 
10403 #undef __FUNCT__
10404 #define __FUNCT__ "DMPlexSetSubpointMap"
10405 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10406 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10407 {
10408   DM_Plex       *mesh = (DM_Plex *) dm->data;
10409   PetscErrorCode ierr;
10410 
10411   PetscFunctionBegin;
10412   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10413   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10414   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
10415   mesh->subpointMap = subpointMap;
10416   ierr = PetscObjectReference((PetscObject) mesh->subpointMap);CHKERRQ(ierr);
10417   PetscFunctionReturn(0);
10418 }
10419 
10420 #undef __FUNCT__
10421 #define __FUNCT__ "DMPlexGetScale"
10422 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10423 {
10424   DM_Plex *mesh = (DM_Plex*) dm->data;
10425 
10426   PetscFunctionBegin;
10427   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10428   PetscValidPointer(scale, 3);
10429   *scale = mesh->scale[unit];
10430   PetscFunctionReturn(0);
10431 }
10432 
10433 #undef __FUNCT__
10434 #define __FUNCT__ "DMPlexSetScale"
10435 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10436 {
10437   DM_Plex *mesh = (DM_Plex*) dm->data;
10438 
10439   PetscFunctionBegin;
10440   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10441   mesh->scale[unit] = scale;
10442   PetscFunctionReturn(0);
10443 }
10444 
10445 
10446 /*******************************************************************************
10447 This should be in a separate Discretization object, but I am not sure how to lay
10448 it out yet, so I am stuffing things here while I experiment.
10449 *******************************************************************************/
10450 #undef __FUNCT__
10451 #define __FUNCT__ "DMPlexSetFEMIntegration"
10452 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10453                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10454                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10455                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10456                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10457                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10458                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10459                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10460                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10461                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10462                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10463                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10464                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10465                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10466                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10467                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10468                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10469 {
10470   DM_Plex *mesh = (DM_Plex*) dm->data;
10471 
10472   PetscFunctionBegin;
10473   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10474   mesh->integrateResidualFEM       = integrateResidualFEM;
10475   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10476   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10477   PetscFunctionReturn(0);
10478 }
10479 
10480 #undef __FUNCT__
10481 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10482 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10483 {
10484   Vec            coordinates;
10485   PetscSection   section, cSection;
10486   PetscInt       dim, vStart, vEnd, v, c, d;
10487   PetscScalar   *values, *cArray;
10488   PetscReal     *coords;
10489   PetscErrorCode ierr;
10490 
10491   PetscFunctionBegin;
10492   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10493   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10494   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10495   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10496   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10497   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10498   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10499   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10500   for (v = vStart; v < vEnd; ++v) {
10501     PetscInt dof, off;
10502 
10503     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10504     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10505     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10506     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
10507     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
10508     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10509   }
10510   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10511   /* Temporary, must be replaced by a projection on the finite element basis */
10512   {
10513     PetscInt eStart = 0, eEnd = 0, e, depth;
10514 
10515     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10516     --depth;
10517     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10518     for (e = eStart; e < eEnd; ++e) {
10519       const PetscInt *cone = PETSC_NULL;
10520       PetscInt        coneSize, d;
10521       PetscScalar    *coordsA, *coordsB;
10522 
10523       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10524       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10525       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10526       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10527       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10528       for (d = 0; d < dim; ++d) {
10529         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10530       }
10531       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
10532       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10533     }
10534   }
10535 
10536   ierr = PetscFree(coords);CHKERRQ(ierr);
10537   ierr = PetscFree(values);CHKERRQ(ierr);
10538 #if 0
10539   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10540   PetscReal      detJ;
10541 
10542   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10543   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10544   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10545 
10546   for (PetscInt c = cStart; c < cEnd; ++c) {
10547     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10548     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10549     const int                          oSize   = pV.getSize();
10550     int                                v       = 0;
10551 
10552     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10553     for (PetscInt cl = 0; cl < oSize; ++cl) {
10554       const PetscInt fDim;
10555 
10556       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10557       if (pointDim) {
10558         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10559           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10560         }
10561       }
10562     }
10563     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10564     pV.clear();
10565   }
10566   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10567   ierr = PetscFree(values);CHKERRQ(ierr);
10568 #endif
10569   PetscFunctionReturn(0);
10570 }
10571 
10572 #undef __FUNCT__
10573 #define __FUNCT__ "DMPlexProjectFunction"
10574 /*@C
10575   DMPlexProjectFunction - This projects the given function into the function space provided.
10576 
10577   Input Parameters:
10578 + dm      - The DM
10579 . numComp - The number of components (functions)
10580 . funcs   - The coordinate functions to evaluate
10581 - mode    - The insertion mode for values
10582 
10583   Output Parameter:
10584 . X - vector
10585 
10586   Level: developer
10587 
10588   Note:
10589   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10590   We will eventually fix it.
10591 
10592 ,seealso: DMPlexComputeL2Diff()
10593 */
10594 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10595 {
10596   Vec            localX;
10597   PetscErrorCode ierr;
10598 
10599   PetscFunctionBegin;
10600   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10601   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10602   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10603   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10604   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10605   PetscFunctionReturn(0);
10606 }
10607 
10608 #undef __FUNCT__
10609 #define __FUNCT__ "DMPlexComputeL2Diff"
10610 /*@C
10611   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10612 
10613   Input Parameters:
10614 + dm    - The DM
10615 . quad  - The PetscQuadrature object for each field
10616 . funcs - The functions to evaluate for each field component
10617 - X     - The coefficient vector u_h
10618 
10619   Output Parameter:
10620 . diff - The diff ||u - u_h||_2
10621 
10622   Level: developer
10623 
10624 .seealso: DMPlexProjectFunction()
10625 */
10626 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10627 {
10628   const PetscInt debug = 0;
10629   PetscSection   section;
10630   Vec            localX;
10631   PetscReal     *coords, *v0, *J, *invJ, detJ;
10632   PetscReal      localDiff = 0.0;
10633   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10634   PetscErrorCode ierr;
10635 
10636   PetscFunctionBegin;
10637   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10638   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10639   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10640   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10641   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10642   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10643   for (field = 0; field < numFields; ++field) {
10644     numComponents += quad[field].numComponents;
10645   }
10646   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10647   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10648   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10649   for (c = cStart; c < cEnd; ++c) {
10650     const PetscScalar *x;
10651     PetscReal          elemDiff = 0.0;
10652 
10653     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10654     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10655     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10656 
10657     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10658       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10659       const PetscReal *quadPoints    = quad[field].quadPoints;
10660       const PetscReal *quadWeights   = quad[field].quadWeights;
10661       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10662       const PetscInt   numBasisComps = quad[field].numComponents;
10663       const PetscReal *basis         = quad[field].basis;
10664       PetscInt         q, d, e, fc, f;
10665 
10666       if (debug) {
10667         char title[1024];
10668         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10669         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10670       }
10671       for (q = 0; q < numQuadPoints; ++q) {
10672         for (d = 0; d < dim; d++) {
10673           coords[d] = v0[d];
10674           for (e = 0; e < dim; e++) {
10675             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10676           }
10677         }
10678         for (fc = 0; fc < numBasisComps; ++fc) {
10679           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10680           PetscReal       interpolant = 0.0;
10681           for (f = 0; f < numBasisFuncs; ++f) {
10682             const PetscInt fidx = f*numBasisComps+fc;
10683             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10684           }
10685           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10686           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10687         }
10688       }
10689       comp        += numBasisComps;
10690       fieldOffset += numBasisFuncs*numBasisComps;
10691     }
10692     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10693     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10694     localDiff += elemDiff;
10695   }
10696   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10697   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10698   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10699   *diff = PetscSqrtReal(*diff);
10700   PetscFunctionReturn(0);
10701 }
10702 
10703 #undef __FUNCT__
10704 #define __FUNCT__ "DMPlexComputeResidualFEM"
10705 /*@
10706   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10707 
10708   Input Parameters:
10709 + dm - The mesh
10710 . X  - Local input vector
10711 - user - The user context
10712 
10713   Output Parameter:
10714 . F  - Local output vector
10715 
10716   Note:
10717   The second member of the user context must be an FEMContext.
10718 
10719   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10720   like a GPU, or vectorize on a multicore machine.
10721 
10722 .seealso: DMPlexComputeJacobianActionFEM()
10723 */
10724 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10725 {
10726   DM_Plex         *mesh = (DM_Plex*) dm->data;
10727   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10728   PetscQuadrature *quad = fem->quad;
10729   PetscSection     section;
10730   PetscReal       *v0, *J, *invJ, *detJ;
10731   PetscScalar     *elemVec, *u;
10732   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10733   PetscInt         cellDof = 0, numComponents = 0;
10734   PetscErrorCode   ierr;
10735 
10736   PetscFunctionBegin;
10737   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10738   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10739   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10740   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10741   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10742   numCells = cEnd - cStart;
10743   for (field = 0; field < numFields; ++field) {
10744     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10745     numComponents += quad[field].numComponents;
10746   }
10747   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10748   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10749   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);
10750   for (c = cStart; c < cEnd; ++c) {
10751     const PetscScalar *x;
10752     PetscInt           i;
10753 
10754     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10755     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10756     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10757 
10758     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10759     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10760   }
10761   for (field = 0; field < numFields; ++field) {
10762     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10763     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10764     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10765     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10766     /* Conforming batches */
10767     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10768     PetscInt numBlocks  = 1;
10769     PetscInt batchSize  = numBlocks * blockSize;
10770     PetscInt numBatches = numBatchesTmp;
10771     PetscInt numChunks  = numCells / (numBatches*batchSize);
10772     /* Remainder */
10773     PetscInt numRemainder = numCells % (numBatches * batchSize);
10774     PetscInt offset       = numCells - numRemainder;
10775 
10776     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10777     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10778                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10779   }
10780   for (c = cStart; c < cEnd; ++c) {
10781     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10782     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10783   }
10784   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10785   if (mesh->printFEM) {
10786     PetscMPIInt rank, numProcs;
10787     PetscInt    p;
10788 
10789     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10790     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10791     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10792     for (p = 0; p < numProcs; ++p) {
10793       if (p == rank) {
10794         Vec f;
10795 
10796         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10797         ierr = VecCopy(F, f);CHKERRQ(ierr);
10798         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10799         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10800         ierr = VecDestroy(&f);CHKERRQ(ierr);
10801         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10802       }
10803       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10804     }
10805   }
10806   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10807   PetscFunctionReturn(0);
10808 }
10809 
10810 #undef __FUNCT__
10811 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10812 /*@C
10813   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10814 
10815   Input Parameters:
10816 + dm - The mesh
10817 . J  - The Jacobian shell matrix
10818 . X  - Local input vector
10819 - user - The user context
10820 
10821   Output Parameter:
10822 . F  - Local output vector
10823 
10824   Note:
10825   The second member of the user context must be an FEMContext.
10826 
10827   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10828   like a GPU, or vectorize on a multicore machine.
10829 
10830 .seealso: DMPlexComputeResidualFEM()
10831 */
10832 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10833 {
10834   DM_Plex         *mesh = (DM_Plex*) dm->data;
10835   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10836   PetscQuadrature *quad = fem->quad;
10837   PetscSection     section;
10838   JacActionCtx    *jctx;
10839   PetscReal       *v0, *J, *invJ, *detJ;
10840   PetscScalar     *elemVec, *u, *a;
10841   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10842   PetscInt         cellDof = 0;
10843   PetscErrorCode   ierr;
10844 
10845   PetscFunctionBegin;
10846   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10847   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10848   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10849   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10850   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10851   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10852   numCells = cEnd - cStart;
10853   for (field = 0; field < numFields; ++field) {
10854     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10855   }
10856   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10857   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);
10858   for (c = cStart; c < cEnd; ++c) {
10859     const PetscScalar *x;
10860     PetscInt           i;
10861 
10862     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10863     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10864     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10865     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10866     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10867     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10868     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
10869     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10870   }
10871   for (field = 0; field < numFields; ++field) {
10872     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10873     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10874     /* Conforming batches */
10875     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10876     PetscInt numBlocks  = 1;
10877     PetscInt batchSize  = numBlocks * blockSize;
10878     PetscInt numBatches = numBatchesTmp;
10879     PetscInt numChunks  = numCells / (numBatches*batchSize);
10880     /* Remainder */
10881     PetscInt numRemainder = numCells % (numBatches * batchSize);
10882     PetscInt offset       = numCells - numRemainder;
10883 
10884     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);
10885     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],
10886                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10887   }
10888   for (c = cStart; c < cEnd; ++c) {
10889     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10890     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10891   }
10892   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10893   if (mesh->printFEM) {
10894     PetscMPIInt rank, numProcs;
10895     PetscInt    p;
10896 
10897     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10898     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10899     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10900     for (p = 0; p < numProcs; ++p) {
10901       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10902       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10903     }
10904   }
10905   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10906   PetscFunctionReturn(0);
10907 }
10908 
10909 #undef __FUNCT__
10910 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10911 /*@
10912   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10913 
10914   Input Parameters:
10915 + dm - The mesh
10916 . X  - Local input vector
10917 - user - The user context
10918 
10919   Output Parameter:
10920 . Jac  - Jacobian matrix
10921 
10922   Note:
10923   The second member of the user context must be an FEMContext.
10924 
10925   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10926   like a GPU, or vectorize on a multicore machine.
10927 
10928 .seealso: FormFunctionLocal()
10929 */
10930 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10931 {
10932   DM_Plex         *mesh = (DM_Plex*) dm->data;
10933   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10934   PetscQuadrature *quad = fem->quad;
10935   PetscSection     section;
10936   PetscReal       *v0, *J, *invJ, *detJ;
10937   PetscScalar     *elemMat, *u;
10938   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10939   PetscInt         cellDof = 0, numComponents = 0;
10940   PetscBool        isShell;
10941   PetscErrorCode   ierr;
10942 
10943   PetscFunctionBegin;
10944   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10945   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10946   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10947   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10948   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10949   numCells = cEnd - cStart;
10950   for (field = 0; field < numFields; ++field) {
10951     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10952     numComponents += quad[field].numComponents;
10953   }
10954   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10955   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10956   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);
10957   for (c = cStart; c < cEnd; ++c) {
10958     const PetscScalar *x;
10959     PetscInt           i;
10960 
10961     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10962     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10963     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10964 
10965     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10966     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10967   }
10968   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10969   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10970     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10971     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10972     PetscInt       fieldJ;
10973 
10974     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10975       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10976       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10977       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10978       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10979       /* Conforming batches */
10980       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10981       PetscInt numBlocks  = 1;
10982       PetscInt batchSize  = numBlocks * blockSize;
10983       PetscInt numBatches = numBatchesTmp;
10984       PetscInt numChunks  = numCells / (numBatches*batchSize);
10985       /* Remainder */
10986       PetscInt numRemainder = numCells % (numBatches * batchSize);
10987       PetscInt offset       = numCells - numRemainder;
10988 
10989       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10990       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10991                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10992     }
10993   }
10994   for (c = cStart; c < cEnd; ++c) {
10995     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10996     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10997   }
10998   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10999 
11000   /* Assemble matrix, using the 2-step process:
11001        MatAssemblyBegin(), MatAssemblyEnd(). */
11002   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11003   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11004 
11005   if (mesh->printFEM) {
11006     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
11007     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
11008     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
11009   }
11010   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
11011   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
11012   if (isShell) {
11013     JacActionCtx *jctx;
11014 
11015     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
11016     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
11017   }
11018   *str = SAME_NONZERO_PATTERN;
11019   PetscFunctionReturn(0);
11020 }
11021 
11022 
11023 #undef __FUNCT__
11024 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
11025 /*@C
11026   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
11027   the local section and an SF describing the section point overlap.
11028 
11029   Input Parameters:
11030   + s - The PetscSection for the local field layout
11031   . sf - The SF describing parallel layout of the section points
11032   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
11033   . label - The label specifying the points
11034   - labelValue - The label stratum specifying the points
11035 
11036   Output Parameter:
11037   . gsection - The PetscSection for the global field layout
11038 
11039   Note: This gives negative sizes and offsets to points not owned by this process
11040 
11041   Level: developer
11042 
11043 .seealso: PetscSectionCreate()
11044 @*/
11045 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
11046 {
11047   PetscInt      *neg;
11048   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
11049   PetscErrorCode ierr;
11050 
11051   PetscFunctionBegin;
11052   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
11053   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
11054   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
11055   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
11056   /* Mark ghost points with negative dof */
11057   for (p = pStart; p < pEnd; ++p) {
11058     PetscInt value;
11059 
11060     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
11061     if (value != labelValue) continue;
11062     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
11063     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
11064     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
11065     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
11066     neg[p-pStart] = -(dof+1);
11067   }
11068   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
11069   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
11070   if (nroots >= 0) {
11071     if (nroots > pEnd - pStart) {
11072       PetscInt *tmpDof;
11073       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11074       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
11075       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11076       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11077       for (p = pStart; p < pEnd; ++p) {
11078         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
11079       }
11080       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
11081     } else {
11082       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11083       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11084     }
11085   }
11086   /* Calculate new sizes, get proccess offset, and calculate point offsets */
11087   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11088     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
11089 
11090     (*gsection)->atlasOff[p] = off;
11091 
11092     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
11093   }
11094   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
11095   globalOff -= off;
11096   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11097     (*gsection)->atlasOff[p] += globalOff;
11098 
11099     neg[p] = -((*gsection)->atlasOff[p]+1);
11100   }
11101   /* Put in negative offsets for ghost points */
11102   if (nroots >= 0) {
11103     if (nroots > pEnd - pStart) {
11104       PetscInt *tmpOff;
11105       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11106       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
11107       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11108       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11109       for (p = pStart; p < pEnd; ++p) {
11110         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
11111       }
11112       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
11113     } else {
11114       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11115       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11116     }
11117   }
11118   ierr = PetscFree(neg);CHKERRQ(ierr);
11119   PetscFunctionReturn(0);
11120 }
11121