xref: /petsc/src/dm/impls/plex/plex.c (revision 2b1f8b2a50766a7608879fd48145510597bea00b)
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     if (markers) {
167       ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
168     }
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors = 3;
180     PetscReal    scale = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\\documentclass{article}\n\n\
191 \\usepackage{tikz}\n\
192 \\usepackage{pgflibraryshapes}\n\
193 \\usetikzlibrary{backgrounds}\n\
194 \\usetikzlibrary{arrows}\n\
195 \\newenvironment{changemargin}[2]{%%\n\
196   \\begin{list}{}{%%\n\
197     \\setlength{\\topsep}{0pt}%%\n\
198     \\setlength{\\leftmargin}{#1}%%\n\
199     \\setlength{\\rightmargin}{#2}%%\n\
200     \\setlength{\\listparindent}{\\parindent}%%\n\
201     \\setlength{\\itemindent}{\\parindent}%%\n\
202     \\setlength{\\parsep}{\\parskip}%%\n\
203   }%%\n\
204   \\item[]}{\\end{list}}\n\n\
205 \\begin{document}\n\
206 \\section{%s}\n\
207 \\begin{changemargin}{-1cm}{0cm}\n\
208 \\begin{center}\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", name, 8.0/scale);CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for(v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for(e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for(c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = PETSC_NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
276     for(p = 0; p < size; ++p) {
277       if (p > 0 && p == size-1) {
278         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
279       } else if (p > 0) {
280         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
281       }
282       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
283     }
284     ierr = PetscViewerASCIIPrintf(viewer, ".\n");CHKERRQ(ierr);
285     ierr = PetscViewerASCIIPrintf(viewer, "\\end{changemargin}\n\
286 \\end{document}\n", name);CHKERRQ(ierr);
287   } else {
288     MPI_Comm    comm = ((PetscObject) dm)->comm;
289     PetscInt   *sizes;
290     PetscInt    locDepth, depth, dim, d;
291     PetscInt    pStart, pEnd, p;
292     PetscMPIInt size;
293 
294     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
295     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
296     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
297     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
298     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
299     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
300     if (depth == 1) {
301       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
302       pEnd = pEnd - pStart;
303       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
304       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
305       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
306       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
307       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
308       pEnd = pEnd - pStart;
309       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
310       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
311       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
312       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
313     } else {
314       for (d = 0; d <= dim; d++) {
315         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
316         pEnd = pEnd - pStart;
317         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
318         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
319         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
320         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
321       }
322     }
323     ierr = PetscFree(sizes);CHKERRQ(ierr);
324   }
325   PetscFunctionReturn(0);
326 }
327 
328 #undef __FUNCT__
329 #define __FUNCT__ "DMView_Plex"
330 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
331 {
332   PetscBool      iascii, isbinary;
333   PetscErrorCode ierr;
334 
335   PetscFunctionBegin;
336   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
337   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
338   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
339   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
340   if (iascii) {
341     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
342 #if 0
343   } else if (isbinary) {
344     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
345 #endif
346   } else SETERRQ1(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"Viewer type %s not supported by this mesh object", ((PetscObject)viewer)->type_name);
347   PetscFunctionReturn(0);
348 }
349 
350 #undef __FUNCT__
351 #define __FUNCT__ "DMDestroy_Plex"
352 PetscErrorCode DMDestroy_Plex(DM dm)
353 {
354   DM_Plex    *mesh = (DM_Plex *) dm->data;
355   DMLabel        next = mesh->labels;
356   PetscErrorCode ierr;
357 
358   PetscFunctionBegin;
359   if (--mesh->refct > 0) {PetscFunctionReturn(0);}
360   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
361   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
362   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
363   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
364   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
365   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
366   while(next) {
367     DMLabel tmp = next->next;
368 
369     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
370     next = tmp;
371   }
372   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
373   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
374   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
375   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
376   ierr = PetscFree(mesh);CHKERRQ(ierr);
377   PetscFunctionReturn(0);
378 }
379 
380 #undef __FUNCT__
381 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
382 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
383 {
384   const PetscInt *support = PETSC_NULL;
385   PetscInt        numAdj  = 0, maxAdjSize = *adjSize, supportSize, s;
386   PetscErrorCode  ierr;
387 
388   PetscFunctionBegin;
389   if (useClosure) {
390     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
391     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
392     for (s = 0; s < supportSize; ++s) {
393       const PetscInt *cone = PETSC_NULL;
394       PetscInt        coneSize, c, q;
395 
396       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
397       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
398       for (c = 0; c < coneSize; ++c) {
399         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
400           if (cone[c] == adj[q]) break;
401         }
402         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
403       }
404     }
405   } else {
406     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
407     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
408     for (s = 0; s < supportSize; ++s) {
409       const PetscInt *cone = PETSC_NULL;
410       PetscInt        coneSize, c, q;
411 
412       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
413       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
414       for (c = 0; c < coneSize; ++c) {
415         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
416           if (cone[c] == adj[q]) break;
417         }
418         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
419       }
420     }
421   }
422   *adjSize = numAdj;
423   PetscFunctionReturn(0);
424 }
425 
426 #undef __FUNCT__
427 #define __FUNCT__ "DMPlexGetAdjacency_Private"
428 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
429 {
430   const PetscInt *star   = tmpClosure;
431   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
432   PetscErrorCode  ierr;
433 
434   PetscFunctionBegin;
435   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt **) &star);CHKERRQ(ierr);
436   for (s = 2; s < starSize*2; s += 2) {
437     const PetscInt *closure = PETSC_NULL;
438     PetscInt        closureSize, c, q;
439 
440     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
441     for (c = 0; c < closureSize*2; c += 2) {
442       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
443         if (closure[c] == adj[q]) break;
444       }
445       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
446     }
447     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
448   }
449   *adjSize = numAdj;
450   PetscFunctionReturn(0);
451 }
452 
453 #undef __FUNCT__
454 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
455 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
456 {
457   DM_Plex *mesh = (DM_Plex *) dm->data;
458 
459   PetscFunctionBegin;
460   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
461   mesh->preallocCenterDim = preallocCenterDim;
462   PetscFunctionReturn(0);
463 }
464 
465 #undef __FUNCT__
466 #define __FUNCT__ "DMPlexPreallocateOperator"
467 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
468 {
469   DM_Plex        *mesh = (DM_Plex *) dm->data;
470   MPI_Comm           comm = ((PetscObject) dm)->comm;
471   PetscSF            sf, sfDof, sfAdj;
472   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
473   PetscInt           nleaves, l, p;
474   const PetscInt    *leaves;
475   const PetscSFNode *remotes;
476   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
477   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
478   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
479   PetscLayout        rLayout;
480   PetscInt           locRows, rStart, rEnd, r;
481   PetscMPIInt        size;
482   PetscBool          useClosure, debug = PETSC_FALSE;
483   PetscErrorCode     ierr;
484 
485   PetscFunctionBegin;
486   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
487   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
488   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
489   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
490   /* Create dof SF based on point SF */
491   if (debug) {
492     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
493     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
494     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
495     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
496     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
497     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
498   }
499   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
500   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
501   if (debug) {
502     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
503     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
504   }
505   /* Create section for dof adjacency (dof ==> # adj dof) */
506   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
507   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
508   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
509   if (mesh->preallocCenterDim == dim) {
510     useClosure = PETSC_FALSE;
511   } else if (mesh->preallocCenterDim == 0) {
512     useClosure = PETSC_TRUE;
513   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
514 
515   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
516   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
517   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
518   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
519   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
520   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
521   /*   Fill in the ghost dofs on the interface */
522   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
523   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
524   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
525   maxClosureSize = (PetscInt) (2*PetscMax(pow((PetscReal) mesh->maxConeSize, depth)+1, pow((PetscReal) mesh->maxSupportSize, depth)+1));
526   maxAdjSize     = (PetscInt) (pow((PetscReal) mesh->maxConeSize, depth)*pow((PetscReal) mesh->maxSupportSize, depth)+1);
527   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
528 
529   /*
530    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
531     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
532        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
533     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
534        Create sfAdj connecting rootSectionAdj and leafSectionAdj
535     3. Visit unowned points on interface, write adjacencies to adj
536        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
537     4. Visit owned points on interface, write adjacencies to rootAdj
538        Remove redundancy in rootAdj
539    ** The last two traversals use transitive closure
540     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
541        Allocate memory addressed by sectionAdj (cols)
542     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
543    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
544   */
545 
546   for (l = 0; l < nleaves; ++l) {
547     PetscInt dof, off, d, q;
548     PetscInt p = leaves[l], numAdj = maxAdjSize;
549 
550     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
551     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
552     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
553     for (q = 0; q < numAdj; ++q) {
554       PetscInt ndof, ncdof;
555 
556       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
557       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
558       for (d = off; d < off+dof; ++d) {
559         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
560       }
561     }
562   }
563   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
564   if (debug) {
565     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
566     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
567   }
568   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
569   if (size > 1) {
570     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
571     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
572   }
573   if (debug) {
574     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
575     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
576   }
577   /* Add in local adjacency sizes for owned dofs on interface (roots) */
578   for (p = pStart; p < pEnd; ++p) {
579     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
580 
581     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
582     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
583     if (!dof) continue;
584     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
585     if (adof <= 0) continue;
586     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
587     for (q = 0; q < numAdj; ++q) {
588       PetscInt ndof, ncdof;
589 
590       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
591       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
592       for (d = off; d < off+dof; ++d) {
593         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
594       }
595     }
596   }
597   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
598   if (debug) {
599     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
600     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
601   }
602   /* Create adj SF based on dof SF */
603   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
604   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
605   if (debug) {
606     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
607     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
608   }
609   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
610   /* Create leaf adjacency */
611   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
612   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
613   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
614   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
615   for (l = 0; l < nleaves; ++l) {
616     PetscInt dof, off, d, q;
617     PetscInt p = leaves[l], numAdj = maxAdjSize;
618 
619     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
620     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
621     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
622     for (d = off; d < off+dof; ++d) {
623       PetscInt aoff, i = 0;
624 
625       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
626       for (q = 0; q < numAdj; ++q) {
627         PetscInt  ndof, ncdof, ngoff, nd;
628 
629         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
630         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
631         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
632         for (nd = 0; nd < ndof-ncdof; ++nd) {
633           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
634           ++i;
635         }
636       }
637     }
638   }
639   /* Debugging */
640   if (debug) {
641     IS tmp;
642     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
643     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
644     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
645   }
646   /* Gather adjacenct indices to root */
647   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
648   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
649   for (r = 0; r < adjSize; ++r) {
650     rootAdj[r] = -1;
651   }
652   if (size > 1) {
653     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
654     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
655   }
656   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
657   ierr = PetscFree(adj);CHKERRQ(ierr);
658   /* Debugging */
659   if (debug) {
660     IS tmp;
661     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
662     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
663     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
664   }
665   /* Add in local adjacency indices for owned dofs on interface (roots) */
666   for (p = pStart; p < pEnd; ++p) {
667     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
668 
669     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
670     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
671     if (!dof) continue;
672     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
673     if (adof <= 0) continue;
674     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
675     for (d = off; d < off+dof; ++d) {
676       PetscInt adof, aoff, i;
677 
678       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
679       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
680       i    = adof-1;
681       for (q = 0; q < numAdj; ++q) {
682         PetscInt ndof, ncdof, ngoff, nd;
683 
684         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
685         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
686         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
687         for (nd = 0; nd < ndof-ncdof; ++nd) {
688           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
689           --i;
690         }
691       }
692     }
693   }
694   /* Debugging */
695   if (debug) {
696     IS tmp;
697     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
698     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
699     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
700   }
701   /* Compress indices */
702   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
703   for (p = pStart; p < pEnd; ++p) {
704     PetscInt dof, cdof, off, d;
705     PetscInt adof, aoff;
706 
707     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
708     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
709     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
710     if (!dof) continue;
711     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
712     if (adof <= 0) continue;
713     for (d = off; d < off+dof-cdof; ++d) {
714       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
715       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
716       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
717       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
718     }
719   }
720   /* Debugging */
721   if (debug) {
722     IS tmp;
723     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
724     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
725     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
726     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
727     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
728   }
729   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
730   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
731   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
732   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
733   for (p = pStart; p < pEnd; ++p) {
734     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
735     PetscBool found  = PETSC_TRUE;
736 
737     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
738     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
739     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
740     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
741     for (d = 0; d < dof-cdof; ++d) {
742       PetscInt ldof, rdof;
743 
744       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
745       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
746       if (ldof > 0) {
747         /* We do not own this point */
748       } else if (rdof > 0) {
749         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
750       } else {
751         found = PETSC_FALSE;
752       }
753     }
754     if (found) continue;
755     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
756     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
757     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
758     for (q = 0; q < numAdj; ++q) {
759       PetscInt ndof, ncdof, noff;
760 
761       /* Adjacent points may not be in the section chart */
762       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
763       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
764       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
765       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
766       for (d = goff; d < goff+dof-cdof; ++d) {
767         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
768       }
769     }
770   }
771   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
772   if (debug) {
773     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
774     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
775   }
776   /* Get adjacent indices */
777   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
778   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
779   for (p = pStart; p < pEnd; ++p) {
780     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
781     PetscBool found  = PETSC_TRUE;
782 
783     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
784     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
785     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
786     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
787     for (d = 0; d < dof-cdof; ++d) {
788       PetscInt ldof, rdof;
789 
790       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
791       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
792       if (ldof > 0) {
793         /* We do not own this point */
794       } else if (rdof > 0) {
795         PetscInt aoff, roff;
796 
797         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
798         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
799         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
800       } else {
801         found = PETSC_FALSE;
802       }
803     }
804     if (found) continue;
805     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
806     for (d = goff; d < goff+dof-cdof; ++d) {
807       PetscInt adof, aoff, i = 0;
808 
809       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
810       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
811       for (q = 0; q < numAdj; ++q) {
812         PetscInt        ndof, ncdof, ngoff, nd;
813         const PetscInt *ncind;
814 
815         /* Adjacent points may not be in the section chart */
816         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
817         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
818         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
819         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
820         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
821         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
822           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
823         }
824       }
825       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
826     }
827   }
828   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
829   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
830   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
831   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
832   /* Debugging */
833   if (debug) {
834     IS tmp;
835     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
836     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
837     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
838   }
839   /* Create allocation vectors from adjacency graph */
840   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
841   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
842   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
843   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
844   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
845   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
846   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
847   /* Only loop over blocks of rows */
848   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
849   for (r = rStart/bs; r < rEnd/bs; ++r) {
850     const PetscInt row = r*bs;
851     PetscInt numCols, cStart, c;
852 
853     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
854     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
855     for (c = cStart; c < cStart+numCols; ++c) {
856       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
857         ++dnz[r-rStart];
858         if (cols[c] >= row) {++dnzu[r-rStart];}
859       } else {
860         ++onz[r-rStart];
861         if (cols[c] >= row) {++onzu[r-rStart];}
862       }
863     }
864   }
865   if (bs > 1) {
866     for (r = 0; r < locRows/bs; ++r) {
867       dnz[r]  /= bs;
868       onz[r]  /= bs;
869       dnzu[r] /= bs;
870       onzu[r] /= bs;
871     }
872   }
873   /* Set matrix pattern */
874   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
875   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
876   /* Fill matrix with zeros */
877   if (fillMatrix) {
878     PetscScalar *values;
879     PetscInt     maxRowLen = 0;
880 
881     for (r = rStart; r < rEnd; ++r) {
882       PetscInt len;
883 
884       ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
885       maxRowLen = PetscMax(maxRowLen, len);
886     }
887     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
888     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
889     for (r = rStart; r < rEnd; ++r) {
890       PetscInt numCols, cStart;
891 
892       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
893       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
894       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
895     }
896     ierr = PetscFree(values);CHKERRQ(ierr);
897     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
898     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
899   }
900   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
901   ierr = PetscFree(cols);CHKERRQ(ierr);
902   PetscFunctionReturn(0);
903 }
904 
905 #if 0
906 #undef __FUNCT__
907 #define __FUNCT__ "DMPlexPreallocateOperator_2"
908 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
909 {
910   PetscErrorCode ierr;
911   PetscInt c,cStart,cEnd,pStart,pEnd;
912   PetscInt *tmpClosure,*tmpAdj,*visits;
913 
914   PetscFunctionBegin;
915   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
916   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
917   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
918   maxClosureSize = 2*PetscMax(pow(mesh->maxConeSize, depth)+1, pow(mesh->maxSupportSize, depth)+1);
919   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
920   npoints = pEnd - pStart;
921   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
922   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
923   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
924   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
925   for (c=cStart; c<cEnd; c++) {
926     PetscInt *support = tmpClosure;
927     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
928     for (p=0; p<supportSize; p++) {
929       lvisits[support[p]]++;
930     }
931   }
932   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
933   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
934   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
935   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
936 
937   ierr = PetscSFGetRanks();CHKERRQ(ierr);
938 
939 
940   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
941   for (c=cStart; c<cEnd; c++) {
942     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
943     /*
944      Depth-first walk of transitive closure.
945      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.
946      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
947      */
948   }
949 
950   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
951   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
952   PetscFunctionReturn(0);
953 }
954 #endif
955 
956 #undef __FUNCT__
957 #define __FUNCT__ "DMCreateMatrix_Plex"
958 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
959 {
960   PetscSection   section, sectionGlobal;
961   PetscInt       bs = -1;
962   PetscInt       localSize;
963   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
964   PetscErrorCode ierr;
965 
966   PetscFunctionBegin;
967 #ifndef PETSC_USE_DYNAMIC_LIBRARIES
968   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
969 #endif
970   if (!mtype) mtype = MATAIJ;
971   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
972   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
973   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
974   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
975   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
976   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
977   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
978   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
979   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
980   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
981   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
982   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
983   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
984   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
985   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
986   /* Check for symmetric storage */
987   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
988   if (isSymmetric) {
989     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
990   }
991   if (!isShell) {
992     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
993     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal;
994 
995     if (bs < 0) {
996       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
997         PetscInt pStart, pEnd, p, dof;
998 
999         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1000         for (p = pStart; p < pEnd; ++p) {
1001           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
1002           if (dof) {
1003             bs = dof;
1004             break;
1005           }
1006         }
1007       } else {
1008         bs = 1;
1009       }
1010       /* Must have same blocksize on all procs (some might have no points) */
1011       bsLocal = bs;
1012       ierr = MPI_Allreduce(&bsLocal, &bs, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
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   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1199   PetscFunctionReturn(0);
1200 }
1201 
1202 #undef __FUNCT__
1203 #define __FUNCT__ "DMPlexGetCone"
1204 /*@C
1205   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1206 
1207   Not collective
1208 
1209   Input Parameters:
1210 + mesh - The DMPlex
1211 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1212 
1213   Output Parameter:
1214 . cone - An array of points which are on the in-edges for point p
1215 
1216   Level: beginner
1217 
1218   Note:
1219   This routine is not available in Fortran.
1220 
1221 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1222 @*/
1223 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1224 {
1225   DM_Plex    *mesh = (DM_Plex *) dm->data;
1226   PetscInt       off;
1227   PetscErrorCode ierr;
1228 
1229   PetscFunctionBegin;
1230   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1231   PetscValidPointer(cone, 3);
1232   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1233   *cone = &mesh->cones[off];
1234   PetscFunctionReturn(0);
1235 }
1236 
1237 #undef __FUNCT__
1238 #define __FUNCT__ "DMPlexSetCone"
1239 /*@
1240   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1241 
1242   Not collective
1243 
1244   Input Parameters:
1245 + mesh - The DMPlex
1246 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1247 - cone - An array of points which are on the in-edges for point p
1248 
1249   Output Parameter:
1250 
1251   Note:
1252   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1253 
1254   Level: beginner
1255 
1256 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1257 @*/
1258 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1259 {
1260   DM_Plex    *mesh = (DM_Plex *) dm->data;
1261   PetscInt       pStart, pEnd;
1262   PetscInt       dof, off, c;
1263   PetscErrorCode ierr;
1264 
1265   PetscFunctionBegin;
1266   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1267   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1268   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1269   if (dof) PetscValidPointer(cone, 3);
1270   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1271   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);
1272   for (c = 0; c < dof; ++c) {
1273     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);
1274     mesh->cones[off+c] = cone[c];
1275   }
1276   PetscFunctionReturn(0);
1277 }
1278 
1279 #undef __FUNCT__
1280 #define __FUNCT__ "DMPlexGetConeOrientation"
1281 /*@C
1282   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1283 
1284   Not collective
1285 
1286   Input Parameters:
1287 + mesh - The DMPlex
1288 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1289 
1290   Output Parameter:
1291 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1292                     integer giving the prescription for cone traversal. If it is negative, the cone is
1293                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1294                     the index of the cone point on which to start.
1295 
1296   Level: beginner
1297 
1298   Note:
1299   This routine is not available in Fortran.
1300 
1301 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1302 @*/
1303 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1304 {
1305   DM_Plex    *mesh = (DM_Plex *) dm->data;
1306   PetscInt       off;
1307   PetscErrorCode ierr;
1308 
1309   PetscFunctionBegin;
1310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1311 #if defined(PETSC_USE_DEBUG)
1312   {
1313     PetscInt dof;
1314     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1315     if (dof) PetscValidPointer(coneOrientation, 3);
1316   }
1317 #endif
1318   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1319   *coneOrientation = &mesh->coneOrientations[off];
1320   PetscFunctionReturn(0);
1321 }
1322 
1323 #undef __FUNCT__
1324 #define __FUNCT__ "DMPlexSetConeOrientation"
1325 /*@
1326   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1327 
1328   Not collective
1329 
1330   Input Parameters:
1331 + mesh - The DMPlex
1332 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1333 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1334                     integer giving the prescription for cone traversal. If it is negative, the cone is
1335                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1336                     the index of the cone point on which to start.
1337 
1338   Output Parameter:
1339 
1340   Note:
1341   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1342 
1343   Level: beginner
1344 
1345 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1346 @*/
1347 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1348 {
1349   DM_Plex    *mesh = (DM_Plex *) dm->data;
1350   PetscInt       pStart, pEnd;
1351   PetscInt       dof, off, c;
1352   PetscErrorCode ierr;
1353 
1354   PetscFunctionBegin;
1355   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1356   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1357   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1358   if (dof) PetscValidPointer(coneOrientation, 3);
1359   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1360   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);
1361   for (c = 0; c < dof; ++c) {
1362     PetscInt cdof, o = coneOrientation[c];
1363 
1364     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1365     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);
1366     mesh->coneOrientations[off+c] = o;
1367   }
1368   PetscFunctionReturn(0);
1369 }
1370 
1371 #undef __FUNCT__
1372 #define __FUNCT__ "DMPlexInsertCone"
1373 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1374 {
1375   DM_Plex    *mesh = (DM_Plex *) dm->data;
1376   PetscInt       pStart, pEnd;
1377   PetscInt       dof, off;
1378   PetscErrorCode ierr;
1379 
1380   PetscFunctionBegin;
1381   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1382   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1383   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1384   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1385   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);
1386   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);
1387   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);
1388   mesh->cones[off+conePos] = conePoint;
1389   PetscFunctionReturn(0);
1390 }
1391 
1392 #undef __FUNCT__
1393 #define __FUNCT__ "DMPlexGetSupportSize"
1394 /*@
1395   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1396 
1397   Not collective
1398 
1399   Input Parameters:
1400 + mesh - The DMPlex
1401 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1402 
1403   Output Parameter:
1404 . size - The support size for point p
1405 
1406   Level: beginner
1407 
1408 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1409 @*/
1410 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1411 {
1412   DM_Plex    *mesh = (DM_Plex *) dm->data;
1413   PetscErrorCode ierr;
1414 
1415   PetscFunctionBegin;
1416   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1417   PetscValidPointer(size, 3);
1418   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1419   PetscFunctionReturn(0);
1420 }
1421 
1422 #undef __FUNCT__
1423 #define __FUNCT__ "DMPlexSetSupportSize"
1424 /*@
1425   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1426 
1427   Not collective
1428 
1429   Input Parameters:
1430 + mesh - The DMPlex
1431 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1432 - size - The support size for point p
1433 
1434   Output Parameter:
1435 
1436   Note:
1437   This should be called after DMPlexSetChart().
1438 
1439   Level: beginner
1440 
1441 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1442 @*/
1443 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1444 {
1445   DM_Plex    *mesh = (DM_Plex *) dm->data;
1446   PetscErrorCode ierr;
1447 
1448   PetscFunctionBegin;
1449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1450   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1451   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1452   PetscFunctionReturn(0);
1453 }
1454 
1455 #undef __FUNCT__
1456 #define __FUNCT__ "DMPlexGetSupport"
1457 /*@C
1458   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1459 
1460   Not collective
1461 
1462   Input Parameters:
1463 + mesh - The DMPlex
1464 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1465 
1466   Output Parameter:
1467 . support - An array of points which are on the out-edges for point p
1468 
1469   Level: beginner
1470 
1471 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1472 @*/
1473 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1474 {
1475   DM_Plex    *mesh = (DM_Plex *) dm->data;
1476   PetscInt       off;
1477   PetscErrorCode ierr;
1478 
1479   PetscFunctionBegin;
1480   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1481   PetscValidPointer(support, 3);
1482   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1483   *support = &mesh->supports[off];
1484   PetscFunctionReturn(0);
1485 }
1486 
1487 #undef __FUNCT__
1488 #define __FUNCT__ "DMPlexSetSupport"
1489 /*@
1490   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1491 
1492   Not collective
1493 
1494   Input Parameters:
1495 + mesh - The DMPlex
1496 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1497 - support - An array of points which are on the in-edges for point p
1498 
1499   Output Parameter:
1500 
1501   Note:
1502   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1503 
1504   Level: beginner
1505 
1506 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1507 @*/
1508 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1509 {
1510   DM_Plex    *mesh = (DM_Plex *) dm->data;
1511   PetscInt       pStart, pEnd;
1512   PetscInt       dof, off, c;
1513   PetscErrorCode ierr;
1514 
1515   PetscFunctionBegin;
1516   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1517   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1518   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1519   if (dof) PetscValidPointer(support, 3);
1520   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1521   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);
1522   for (c = 0; c < dof; ++c) {
1523     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);
1524     mesh->supports[off+c] = support[c];
1525   }
1526   PetscFunctionReturn(0);
1527 }
1528 
1529 #undef __FUNCT__
1530 #define __FUNCT__ "DMPlexInsertSupport"
1531 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1532 {
1533   DM_Plex    *mesh = (DM_Plex *) dm->data;
1534   PetscInt       pStart, pEnd;
1535   PetscInt       dof, off;
1536   PetscErrorCode ierr;
1537 
1538   PetscFunctionBegin;
1539   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1540   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1541   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1542   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1543   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);
1544   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);
1545   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);
1546   mesh->supports[off+supportPos] = supportPoint;
1547   PetscFunctionReturn(0);
1548 }
1549 
1550 #undef __FUNCT__
1551 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1552 /*@C
1553   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1554 
1555   Not collective
1556 
1557   Input Parameters:
1558 + mesh - The DMPlex
1559 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1560 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1561 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1562 
1563   Output Parameters:
1564 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1565 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1566 
1567   Note:
1568   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1569 
1570   Level: beginner
1571 
1572 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1573 @*/
1574 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1575 {
1576   DM_Plex     *mesh = (DM_Plex *) dm->data;
1577   PetscInt       *closure, *fifo;
1578   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1579   PetscInt        tmpSize, t;
1580   PetscInt        depth = 0, maxSize;
1581   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1582   PetscErrorCode  ierr;
1583 
1584   PetscFunctionBegin;
1585   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1586   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1587   maxSize = (PetscInt) (2*PetscMax(PetscMax(pow((PetscReal) mesh->maxConeSize, depth)+1, pow((PetscReal) mesh->maxSupportSize, depth)+1), depth+1));
1588   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1589   if (*points) {
1590     closure = *points;
1591   } else {
1592     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1593   }
1594   closure[0] = p; closure[1] = 0;
1595   /* This is only 1-level */
1596   if (useCone) {
1597     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1598     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1599     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1600   } else {
1601     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1602     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1603   }
1604   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1605     const PetscInt cp = tmp[t];
1606     const PetscInt co = tmpO ? tmpO[t] : 0;
1607 
1608     closure[closureSize]   = cp;
1609     closure[closureSize+1] = co;
1610     fifo[fifoSize]         = cp;
1611     fifo[fifoSize+1]       = co;
1612   }
1613   while(fifoSize - fifoStart) {
1614     const PetscInt q   = fifo[fifoStart];
1615     const PetscInt o   = fifo[fifoStart+1];
1616     const PetscInt rev = o >= 0 ? 0 : 1;
1617     const PetscInt off = rev ? -(o+1) : o;
1618 
1619     if (useCone) {
1620       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1621       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1622       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1623     } else {
1624       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1625       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1626       tmpO = PETSC_NULL;
1627     }
1628     for (t = 0; t < tmpSize; ++t) {
1629       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1630       const PetscInt cp = tmp[i];
1631       /* Must propogate orientation */
1632       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1633       PetscInt       c;
1634 
1635       /* Check for duplicate */
1636       for (c = 0; c < closureSize; c += 2) {
1637         if (closure[c] == cp) break;
1638       }
1639       if (c == closureSize) {
1640         closure[closureSize]   = cp;
1641         closure[closureSize+1] = co;
1642         fifo[fifoSize]         = cp;
1643         fifo[fifoSize+1]       = co;
1644         closureSize += 2;
1645         fifoSize    += 2;
1646       }
1647     }
1648     fifoStart += 2;
1649   }
1650   if (numPoints) *numPoints = closureSize/2;
1651   if (points)    *points    = closure;
1652   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1653   PetscFunctionReturn(0);
1654 }
1655 
1656 #undef __FUNCT__
1657 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1658 /*@C
1659   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1660 
1661   Not collective
1662 
1663   Input Parameters:
1664 + mesh - The DMPlex
1665 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1666 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1667 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1668 
1669   Output Parameters:
1670 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1671 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1672 
1673   Note:
1674   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1675 
1676   Level: beginner
1677 
1678 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1679 @*/
1680 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1681 {
1682   PetscErrorCode  ierr;
1683 
1684   PetscFunctionBegin;
1685   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1686   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1687   PetscFunctionReturn(0);
1688 }
1689 
1690 #undef __FUNCT__
1691 #define __FUNCT__ "DMPlexGetFaces"
1692 /*
1693   DMPlexGetFaces -
1694 
1695   Note: This will only work for cell-vertex meshes.
1696 */
1697 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1698 {
1699   DM_Plex     *mesh  = (DM_Plex *) dm->data;
1700   const PetscInt *cone  = PETSC_NULL;
1701   PetscInt        depth = 0, dim, coneSize;
1702   PetscErrorCode  ierr;
1703 
1704   PetscFunctionBegin;
1705   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1706   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1707   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1708   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1709   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1710   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1711   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1712   switch(dim) {
1713   case 2:
1714     switch(coneSize) {
1715     case 3:
1716       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1717       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1718       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1719       *numFaces = 3;
1720       *faceSize = 2;
1721       *faces    = mesh->facesTmp;
1722       break;
1723     case 4:
1724       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1725       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1726       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1727       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1728       *numFaces = 4;
1729       *faceSize = 2;
1730       *faces    = mesh->facesTmp;
1731       break;
1732     default:
1733       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1734     }
1735     break;
1736   case 3:
1737     switch(coneSize) {
1738     case 3:
1739       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1740       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1741       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1742       *numFaces = 3;
1743       *faceSize = 2;
1744       *faces    = mesh->facesTmp;
1745       break;
1746     case 4:
1747       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1748       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1749       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1750       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1751       *numFaces = 4;
1752       *faceSize = 3;
1753       *faces    = mesh->facesTmp;
1754       break;
1755     default:
1756       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1757     }
1758     break;
1759   default:
1760     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1761   }
1762   PetscFunctionReturn(0);
1763 }
1764 
1765 #undef __FUNCT__
1766 #define __FUNCT__ "DMPlexGetMaxSizes"
1767 /*@
1768   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1769 
1770   Not collective
1771 
1772   Input Parameter:
1773 . mesh - The DMPlex
1774 
1775   Output Parameters:
1776 + maxConeSize - The maximum number of in-edges
1777 - maxSupportSize - The maximum number of out-edges
1778 
1779   Level: beginner
1780 
1781 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1782 @*/
1783 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1784 {
1785   DM_Plex *mesh = (DM_Plex *) dm->data;
1786 
1787   PetscFunctionBegin;
1788   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1789   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1790   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1791   PetscFunctionReturn(0);
1792 }
1793 
1794 #undef __FUNCT__
1795 #define __FUNCT__ "DMSetUp_Plex"
1796 PetscErrorCode DMSetUp_Plex(DM dm)
1797 {
1798   DM_Plex    *mesh = (DM_Plex *) dm->data;
1799   PetscInt       size;
1800   PetscErrorCode ierr;
1801 
1802   PetscFunctionBegin;
1803   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1804   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1805   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1806   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1807   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1808   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1809   if (mesh->maxSupportSize) {
1810     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1811     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1812     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1813   }
1814   PetscFunctionReturn(0);
1815 }
1816 
1817 #undef __FUNCT__
1818 #define __FUNCT__ "DMCreateSubDM_Plex"
1819 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1820 {
1821   PetscSection   section, sectionGlobal;
1822   PetscInt      *subIndices;
1823   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1824   PetscErrorCode ierr;
1825 
1826   PetscFunctionBegin;
1827   if (!numFields) PetscFunctionReturn(0);
1828   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1829   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1830   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1831   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1832   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1833   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);
1834   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1835   for (p = pStart; p < pEnd; ++p) {
1836     PetscInt gdof;
1837 
1838     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1839     if (gdof > 0) {
1840       for (f = 0; f < numFields; ++f) {
1841         PetscInt fdof, fcdof;
1842 
1843         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1844         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1845         subSize += fdof-fcdof;
1846       }
1847     }
1848   }
1849   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1850   for (p = pStart; p < pEnd; ++p) {
1851     PetscInt gdof, goff;
1852 
1853     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1854     if (gdof > 0) {
1855       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1856       for (f = 0; f < numFields; ++f) {
1857         PetscInt fdof, fcdof, fc, f2, poff = 0;
1858 
1859         /* Can get rid of this loop by storing field information in the global section */
1860         for (f2 = 0; f2 < fields[f]; ++f2) {
1861           ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1862           ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1863           poff += fdof-fcdof;
1864         }
1865         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1866         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1867         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1868           subIndices[subOff] = goff+poff+fc;
1869         }
1870       }
1871     }
1872   }
1873   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1874   if (subdm) {
1875     PetscSection subsection;
1876     PetscBool    haveNull = PETSC_FALSE;
1877     PetscInt     f, nf = 0;
1878 
1879     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1880     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1881     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1882     for (f = 0; f < numFields; ++f) {
1883       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1884       if ((*subdm)->nullspaceConstructors[f]) {
1885         haveNull = PETSC_TRUE;
1886         nf       = f;
1887       }
1888     }
1889     if (haveNull) {
1890       MatNullSpace nullSpace;
1891 
1892       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1893       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1894       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1895     }
1896     if (dm->fields) {
1897       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);
1898       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1899       for (f = 0; f < numFields; ++f) {
1900         ierr = PetscOListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);
1901       }
1902       if (numFields == 1) {
1903         MatNullSpace space;
1904         Mat          pmat;
1905 
1906         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject *) &space);CHKERRQ(ierr);
1907         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1908         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject *) &space);CHKERRQ(ierr);
1909         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1910         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject *) &pmat);CHKERRQ(ierr);
1911         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1912       }
1913     }
1914   }
1915   PetscFunctionReturn(0);
1916 }
1917 
1918 #undef __FUNCT__
1919 #define __FUNCT__ "DMPlexSymmetrize"
1920 /*@
1921   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1922 
1923   Not collective
1924 
1925   Input Parameter:
1926 . mesh - The DMPlex
1927 
1928   Output Parameter:
1929 
1930   Note:
1931   This should be called after all calls to DMPlexSetCone()
1932 
1933   Level: beginner
1934 
1935 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1936 @*/
1937 PetscErrorCode DMPlexSymmetrize(DM dm)
1938 {
1939   DM_Plex    *mesh = (DM_Plex *) dm->data;
1940   PetscInt      *offsets;
1941   PetscInt       supportSize;
1942   PetscInt       pStart, pEnd, p;
1943   PetscErrorCode ierr;
1944 
1945   PetscFunctionBegin;
1946   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1947   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1948   /* Calculate support sizes */
1949   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1950   for (p = pStart; p < pEnd; ++p) {
1951     PetscInt dof, off, c;
1952 
1953     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1954     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1955     for (c = off; c < off+dof; ++c) {
1956       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1957     }
1958   }
1959   for (p = pStart; p < pEnd; ++p) {
1960     PetscInt dof;
1961 
1962     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1963     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1964   }
1965   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1966   /* Calculate supports */
1967   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1968   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1969   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1970   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1971   for (p = pStart; p < pEnd; ++p) {
1972     PetscInt dof, off, c;
1973 
1974     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1975     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1976     for (c = off; c < off+dof; ++c) {
1977       const PetscInt q = mesh->cones[c];
1978       PetscInt       offS;
1979 
1980       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1981       mesh->supports[offS+offsets[q]] = p;
1982       ++offsets[q];
1983     }
1984   }
1985   ierr = PetscFree(offsets);CHKERRQ(ierr);
1986   PetscFunctionReturn(0);
1987 }
1988 
1989 #undef __FUNCT__
1990 #define __FUNCT__ "DMPlexSetDepth_Private"
1991 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1992 {
1993   PetscInt       d;
1994   PetscErrorCode ierr;
1995 
1996   PetscFunctionBegin;
1997   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1998   if (d < 0) {
1999     /* We are guaranteed that the point has a cone since the depth was not yet set */
2000     const PetscInt *cone = PETSC_NULL;
2001     PetscInt        dCone;
2002 
2003     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2004     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2005     d    = dCone+1;
2006     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2007   }
2008   *depth = d;
2009   PetscFunctionReturn(0);
2010 }
2011 
2012 #undef __FUNCT__
2013 #define __FUNCT__ "DMPlexStratify"
2014 /*@
2015   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2016   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2017   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2018   the DAG.
2019 
2020   Not collective
2021 
2022   Input Parameter:
2023 . mesh - The DMPlex
2024 
2025   Output Parameter:
2026 
2027   Notes:
2028   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2029   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2030 
2031   This should be called after all calls to DMPlexSymmetrize()
2032 
2033   Level: beginner
2034 
2035 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2036 @*/
2037 PetscErrorCode DMPlexStratify(DM dm)
2038 {
2039   DM_Plex    *mesh = (DM_Plex *) dm->data;
2040   PetscInt       pStart, pEnd, p;
2041   PetscInt       numRoots = 0, numLeaves = 0;
2042   PetscErrorCode ierr;
2043 
2044   PetscFunctionBegin;
2045   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2046   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2047   /* Calculate depth */
2048   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2049   /* Initialize roots and count leaves */
2050   for (p = pStart; p < pEnd; ++p) {
2051     PetscInt coneSize, supportSize;
2052 
2053     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2054     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2055     if (!coneSize && supportSize) {
2056       ++numRoots;
2057       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2058     } else if (!supportSize && coneSize) {
2059       ++numLeaves;
2060     } else if (!supportSize && !coneSize) {
2061       /* Isolated points */
2062       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2063     }
2064   }
2065   if (numRoots + numLeaves == (pEnd - pStart)) {
2066     for (p = pStart; p < pEnd; ++p) {
2067       PetscInt coneSize, supportSize;
2068 
2069       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2070       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2071       if (!supportSize && coneSize) {
2072         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2073       }
2074     }
2075   } else {
2076     /* This might be slow since lookup is not fast */
2077     for (p = pStart; p < pEnd; ++p) {
2078       PetscInt depth;
2079 
2080       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2081     }
2082   }
2083   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2084   PetscFunctionReturn(0);
2085 }
2086 
2087 #undef __FUNCT__
2088 #define __FUNCT__ "DMPlexGetJoin"
2089 /*@C
2090   DMPlexGetJoin - Get an array for the join of the set of points
2091 
2092   Not Collective
2093 
2094   Input Parameters:
2095 + dm - The DMPlex object
2096 . numPoints - The number of input points for the join
2097 - points - The input points
2098 
2099   Output Parameters:
2100 + numCoveredPoints - The number of points in the join
2101 - coveredPoints - The points in the join
2102 
2103   Level: intermediate
2104 
2105   Note: Currently, this is restricted to a single level join
2106 
2107 .keywords: mesh
2108 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2109 @*/
2110 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2111 {
2112   DM_Plex    *mesh = (DM_Plex *) dm->data;
2113   PetscInt      *join[2];
2114   PetscInt       joinSize, i = 0;
2115   PetscInt       dof, off, p, c, m;
2116   PetscErrorCode ierr;
2117 
2118   PetscFunctionBegin;
2119   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2120   PetscValidPointer(points, 2);
2121   PetscValidPointer(numCoveredPoints, 3);
2122   PetscValidPointer(coveredPoints, 4);
2123   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2124   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2125   /* Copy in support of first point */
2126   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2127   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2128   for (joinSize = 0; joinSize < dof; ++joinSize) {
2129     join[i][joinSize] = mesh->supports[off+joinSize];
2130   }
2131   /* Check each successive support */
2132   for (p = 1; p < numPoints; ++p) {
2133     PetscInt newJoinSize = 0;
2134 
2135     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2136     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2137     for (c = 0; c < dof; ++c) {
2138       const PetscInt point = mesh->supports[off+c];
2139 
2140       for (m = 0; m < joinSize; ++m) {
2141         if (point == join[i][m]) {
2142           join[1-i][newJoinSize++] = point;
2143           break;
2144         }
2145       }
2146     }
2147     joinSize = newJoinSize;
2148     i = 1-i;
2149   }
2150   *numCoveredPoints = joinSize;
2151   *coveredPoints    = join[i];
2152   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2153   PetscFunctionReturn(0);
2154 }
2155 
2156 #undef __FUNCT__
2157 #define __FUNCT__ "DMPlexRestoreJoin"
2158 /*@C
2159   DMPlexRestoreJoin - Restore an array for the join of the set of points
2160 
2161   Not Collective
2162 
2163   Input Parameters:
2164 + dm - The DMPlex object
2165 . numPoints - The number of input points for the join
2166 - points - The input points
2167 
2168   Output Parameters:
2169 + numCoveredPoints - The number of points in the join
2170 - coveredPoints - The points in the join
2171 
2172   Level: intermediate
2173 
2174 .keywords: mesh
2175 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2176 @*/
2177 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2178 {
2179   PetscErrorCode ierr;
2180 
2181   PetscFunctionBegin;
2182   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2183   PetscValidPointer(coveredPoints, 4);
2184   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2185   PetscFunctionReturn(0);
2186 }
2187 
2188 #undef __FUNCT__
2189 #define __FUNCT__ "DMPlexGetFullJoin"
2190 /*@C
2191   DMPlexGetFullJoin - Get an array for the join of the set of points
2192 
2193   Not Collective
2194 
2195   Input Parameters:
2196 + dm - The DMPlex object
2197 . numPoints - The number of input points for the join
2198 - points - The input points
2199 
2200   Output Parameters:
2201 + numCoveredPoints - The number of points in the join
2202 - coveredPoints - The points in the join
2203 
2204   Level: intermediate
2205 
2206 .keywords: mesh
2207 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2208 @*/
2209 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2210 {
2211   DM_Plex    *mesh = (DM_Plex *) dm->data;
2212   PetscInt      *offsets, **closures;
2213   PetscInt      *join[2];
2214   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2215   PetscInt       p, d, c, m;
2216   PetscErrorCode ierr;
2217 
2218   PetscFunctionBegin;
2219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2220   PetscValidPointer(points, 2);
2221   PetscValidPointer(numCoveredPoints, 3);
2222   PetscValidPointer(coveredPoints, 4);
2223 
2224   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2225   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2226   ierr = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2227   ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2228   maxSize = (PetscInt) (pow((PetscReal) mesh->maxSupportSize, depth)+1);
2229   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2230   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2231 
2232   for (p = 0; p < numPoints; ++p) {
2233     PetscInt closureSize;
2234 
2235     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2236     offsets[p*(depth+2)+0] = 0;
2237     for (d = 0; d < depth+1; ++d) {
2238       PetscInt pStart, pEnd, i;
2239 
2240       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2241       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2242         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2243           offsets[p*(depth+2)+d+1] = i;
2244           break;
2245         }
2246       }
2247       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2248     }
2249     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);
2250   }
2251   for (d = 0; d < depth+1; ++d) {
2252     PetscInt dof;
2253 
2254     /* Copy in support of first point */
2255     dof = offsets[d+1] - offsets[d];
2256     for (joinSize = 0; joinSize < dof; ++joinSize) {
2257       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2258     }
2259     /* Check each successive cone */
2260     for (p = 1; p < numPoints && joinSize; ++p) {
2261       PetscInt newJoinSize = 0;
2262 
2263       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2264       for (c = 0; c < dof; ++c) {
2265         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2266 
2267         for (m = 0; m < joinSize; ++m) {
2268           if (point == join[i][m]) {
2269             join[1-i][newJoinSize++] = point;
2270             break;
2271           }
2272         }
2273       }
2274       joinSize = newJoinSize;
2275       i = 1-i;
2276     }
2277     if (joinSize) break;
2278   }
2279   *numCoveredPoints = joinSize;
2280   *coveredPoints    = join[i];
2281   for (p = 0; p < numPoints; ++p) {
2282     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2283   }
2284   ierr = PetscFree(closures);CHKERRQ(ierr);
2285   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2286   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2287   PetscFunctionReturn(0);
2288 }
2289 
2290 #undef __FUNCT__
2291 #define __FUNCT__ "DMPlexGetMeet"
2292 /*@C
2293   DMPlexGetMeet - Get an array for the meet of the set of points
2294 
2295   Not Collective
2296 
2297   Input Parameters:
2298 + dm - The DMPlex object
2299 . numPoints - The number of input points for the meet
2300 - points - The input points
2301 
2302   Output Parameters:
2303 + numCoveredPoints - The number of points in the meet
2304 - coveredPoints - The points in the meet
2305 
2306   Level: intermediate
2307 
2308   Note: Currently, this is restricted to a single level meet
2309 
2310 .keywords: mesh
2311 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2312 @*/
2313 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2314 {
2315   DM_Plex    *mesh = (DM_Plex *) dm->data;
2316   PetscInt      *meet[2];
2317   PetscInt       meetSize, i = 0;
2318   PetscInt       dof, off, p, c, m;
2319   PetscErrorCode ierr;
2320 
2321   PetscFunctionBegin;
2322   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2323   PetscValidPointer(points, 2);
2324   PetscValidPointer(numCoveringPoints, 3);
2325   PetscValidPointer(coveringPoints, 4);
2326   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2327   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2328   /* Copy in cone of first point */
2329   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2330   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2331   for (meetSize = 0; meetSize < dof; ++meetSize) {
2332     meet[i][meetSize] = mesh->cones[off+meetSize];
2333   }
2334   /* Check each successive cone */
2335   for (p = 1; p < numPoints; ++p) {
2336     PetscInt newMeetSize = 0;
2337 
2338     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2339     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2340     for (c = 0; c < dof; ++c) {
2341       const PetscInt point = mesh->cones[off+c];
2342 
2343       for (m = 0; m < meetSize; ++m) {
2344         if (point == meet[i][m]) {
2345           meet[1-i][newMeetSize++] = point;
2346           break;
2347         }
2348       }
2349     }
2350     meetSize = newMeetSize;
2351     i = 1-i;
2352   }
2353   *numCoveringPoints = meetSize;
2354   *coveringPoints    = meet[i];
2355   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2356   PetscFunctionReturn(0);
2357 }
2358 
2359 #undef __FUNCT__
2360 #define __FUNCT__ "DMPlexRestoreMeet"
2361 /*@C
2362   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2363 
2364   Not Collective
2365 
2366   Input Parameters:
2367 + dm - The DMPlex object
2368 . numPoints - The number of input points for the meet
2369 - points - The input points
2370 
2371   Output Parameters:
2372 + numCoveredPoints - The number of points in the meet
2373 - coveredPoints - The points in the meet
2374 
2375   Level: intermediate
2376 
2377 .keywords: mesh
2378 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2379 @*/
2380 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2381 {
2382   PetscErrorCode ierr;
2383 
2384   PetscFunctionBegin;
2385   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2386   PetscValidPointer(coveredPoints, 4);
2387   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2388   PetscFunctionReturn(0);
2389 }
2390 
2391 #undef __FUNCT__
2392 #define __FUNCT__ "DMPlexGetFullMeet"
2393 /*@C
2394   DMPlexGetFullMeet - Get an array for the meet of the set of points
2395 
2396   Not Collective
2397 
2398   Input Parameters:
2399 + dm - The DMPlex object
2400 . numPoints - The number of input points for the meet
2401 - points - The input points
2402 
2403   Output Parameters:
2404 + numCoveredPoints - The number of points in the meet
2405 - coveredPoints - The points in the meet
2406 
2407   Level: intermediate
2408 
2409 .keywords: mesh
2410 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2411 @*/
2412 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2413 {
2414   DM_Plex    *mesh = (DM_Plex *) dm->data;
2415   PetscInt      *offsets, **closures;
2416   PetscInt      *meet[2];
2417   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2418   PetscInt       p, h, c, m;
2419   PetscErrorCode ierr;
2420 
2421   PetscFunctionBegin;
2422   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2423   PetscValidPointer(points, 2);
2424   PetscValidPointer(numCoveredPoints, 3);
2425   PetscValidPointer(coveredPoints, 4);
2426 
2427   ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2428   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2429   ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2430   maxSize = (PetscInt) (pow((PetscReal) mesh->maxConeSize, height)+1);
2431   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2432   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2433 
2434   for (p = 0; p < numPoints; ++p) {
2435     PetscInt closureSize;
2436 
2437     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2438     offsets[p*(height+2)+0] = 0;
2439     for (h = 0; h < height+1; ++h) {
2440       PetscInt pStart, pEnd, i;
2441 
2442       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2443       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2444         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2445           offsets[p*(height+2)+h+1] = i;
2446           break;
2447         }
2448       }
2449       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2450     }
2451     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);
2452   }
2453   for (h = 0; h < height+1; ++h) {
2454     PetscInt dof;
2455 
2456     /* Copy in cone of first point */
2457     dof = offsets[h+1] - offsets[h];
2458     for (meetSize = 0; meetSize < dof; ++meetSize) {
2459       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2460     }
2461     /* Check each successive cone */
2462     for (p = 1; p < numPoints && meetSize; ++p) {
2463       PetscInt newMeetSize = 0;
2464 
2465       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2466       for (c = 0; c < dof; ++c) {
2467         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2468 
2469         for (m = 0; m < meetSize; ++m) {
2470           if (point == meet[i][m]) {
2471             meet[1-i][newMeetSize++] = point;
2472             break;
2473           }
2474         }
2475       }
2476       meetSize = newMeetSize;
2477       i = 1-i;
2478     }
2479     if (meetSize) break;
2480   }
2481   *numCoveredPoints = meetSize;
2482   *coveredPoints    = meet[i];
2483   for (p = 0; p < numPoints; ++p) {
2484     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2485   }
2486   ierr = PetscFree(closures);CHKERRQ(ierr);
2487   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2488   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2489   PetscFunctionReturn(0);
2490 }
2491 
2492 #undef __FUNCT__
2493 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2494 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices) {
2495   MPI_Comm       comm = ((PetscObject) dm)->comm;
2496   PetscInt       cellDim;
2497   PetscErrorCode ierr;
2498 
2499   PetscFunctionBegin;
2500   PetscValidPointer(numFaceVertices,3);
2501   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2502   switch(cellDim) {
2503   case 0:
2504     *numFaceVertices = 0;
2505     break;
2506   case 1:
2507     *numFaceVertices = 1;
2508     break;
2509   case 2:
2510     switch(numCorners) {
2511     case 3: // triangle
2512       *numFaceVertices = 2; // Edge has 2 vertices
2513       break;
2514     case 4: // quadrilateral
2515       *numFaceVertices = 2; // Edge has 2 vertices
2516       break;
2517     case 6: // quadratic triangle, tri and quad cohesive Lagrange cells
2518       *numFaceVertices = 3; // Edge has 3 vertices
2519       break;
2520     case 9: // quadratic quadrilateral, quadratic quad cohesive Lagrange cells
2521       *numFaceVertices = 3; // Edge has 3 vertices
2522       break;
2523     default:
2524       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2525     }
2526     break;
2527   case 3:
2528     switch(numCorners)	{
2529     case 4: // tetradehdron
2530       *numFaceVertices = 3; // Face has 3 vertices
2531       break;
2532     case 6: // tet cohesive cells
2533       *numFaceVertices = 4; // Face has 4 vertices
2534       break;
2535     case 8: // hexahedron
2536       *numFaceVertices = 4; // Face has 4 vertices
2537       break;
2538     case 9: // tet cohesive Lagrange cells
2539       *numFaceVertices = 6; // Face has 6 vertices
2540       break;
2541     case 10: // quadratic tetrahedron
2542       *numFaceVertices = 6; // Face has 6 vertices
2543       break;
2544     case 12: // hex cohesive Lagrange cells
2545       *numFaceVertices = 6; // Face has 6 vertices
2546       break;
2547     case 18: // quadratic tet cohesive Lagrange cells
2548       *numFaceVertices = 6; // Face has 6 vertices
2549       break;
2550     case 27: // quadratic hexahedron, quadratic hex cohesive Lagrange cells
2551       *numFaceVertices = 9; // Face has 9 vertices
2552       break;
2553     default:
2554       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2555     }
2556     break;
2557   default:
2558     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2559   }
2560   PetscFunctionReturn(0);
2561 }
2562 
2563 #undef __FUNCT__
2564 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2565 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency) {
2566   const PetscInt maxFaceCases = 30;
2567   PetscInt       numFaceCases = 0;
2568   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2569   PetscInt      *off, *adj;
2570   PetscInt      *neighborCells, *tmpClosure;
2571   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2572   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2573   PetscErrorCode ierr;
2574 
2575   PetscFunctionBegin;
2576   /* For parallel partitioning, I think you have to communicate supports */
2577   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2578   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2579   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2580   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2581   if (cEnd - cStart == 0) {
2582     if (numVertices) *numVertices = 0;
2583     if (offsets)     *offsets     = PETSC_NULL;
2584     if (adjacency)   *adjacency   = PETSC_NULL;
2585     PetscFunctionReturn(0);
2586   }
2587   numCells = cEnd - cStart;
2588   /* Setup face recognition */
2589   {
2590     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 */
2591 
2592     for (c = cStart; c < cEnd; ++c) {
2593       PetscInt corners;
2594 
2595       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2596       if (!cornersSeen[corners]) {
2597         PetscInt nFV;
2598 
2599         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2600         cornersSeen[corners] = 1;
2601         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2602         numFaceVertices[numFaceCases++] = nFV;
2603       }
2604     }
2605   }
2606   maxClosure   = (PetscInt) (2*PetscMax(pow((PetscReal) maxConeSize, depth)+1, pow((PetscReal) maxSupportSize, depth)+1));
2607   maxNeighbors = (PetscInt) (pow((PetscReal) maxConeSize, depth)*pow((PetscReal) maxSupportSize, depth)+1);
2608   ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2609   ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2610   ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2611   /* Count neighboring cells */
2612   for (cell = cStart; cell < cEnd; ++cell) {
2613     PetscInt numNeighbors = maxNeighbors, n;
2614 
2615     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2616     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2617     for (n = 0; n < numNeighbors; ++n) {
2618       PetscInt        cellPair[2] = {cell, neighborCells[n]};
2619       PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2620       PetscInt        meetSize    = 0;
2621       const PetscInt *meet        = PETSC_NULL;
2622 
2623       if (cellPair[0] == cellPair[1]) continue;
2624       if (!found) {
2625         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2626         if (meetSize) {
2627           PetscInt f;
2628 
2629           for (f = 0; f < numFaceCases; ++f) {
2630             if (numFaceVertices[f] == meetSize) {
2631               found = PETSC_TRUE;
2632               break;
2633             }
2634           }
2635         }
2636         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2637       }
2638       if (found) {
2639         ++off[cell-cStart+1];
2640       }
2641     }
2642   }
2643   /* Prefix sum */
2644   for (cell = 1; cell <= numCells; ++cell) {
2645     off[cell] += off[cell-1];
2646   }
2647   if (adjacency) {
2648     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2649     /* Get neighboring cells */
2650     for (cell = cStart; cell < cEnd; ++cell) {
2651       PetscInt numNeighbors = maxNeighbors, n;
2652       PetscInt cellOffset   = 0;
2653 
2654       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2655       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2656       for (n = 0; n < numNeighbors; ++n) {
2657         PetscInt        cellPair[2] = {cell, neighborCells[n]};
2658         PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2659         PetscInt        meetSize    = 0;
2660         const PetscInt *meet        = PETSC_NULL;
2661 
2662         if (cellPair[0] == cellPair[1]) continue;
2663         if (!found) {
2664           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2665           if (meetSize) {
2666             PetscInt f;
2667 
2668             for (f = 0; f < numFaceCases; ++f) {
2669               if (numFaceVertices[f] == meetSize) {
2670                 found = PETSC_TRUE;
2671                 break;
2672               }
2673             }
2674           }
2675           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2676         }
2677         if (found) {
2678           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2679           ++cellOffset;
2680         }
2681       }
2682     }
2683   }
2684   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2685   if (numVertices) *numVertices = numCells;
2686   if (offsets)     *offsets     = off;
2687   if (adjacency)   *adjacency   = adj;
2688   PetscFunctionReturn(0);
2689 }
2690 
2691 #ifdef PETSC_HAVE_CHACO
2692 #ifdef PETSC_HAVE_UNISTD_H
2693 #include <unistd.h>
2694 #endif
2695 /* Chaco does not have an include file */
2696 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2697                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2698                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2699                        int mesh_dims[3], double *goal, int global_method, int local_method,
2700                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2701 
2702 extern int FREE_GRAPH;
2703 
2704 #undef __FUNCT__
2705 #define __FUNCT__ "DMPlexPartition_Chaco"
2706 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2707 {
2708   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2709   MPI_Comm comm = ((PetscObject) dm)->comm;
2710   int nvtxs = numVertices;                /* number of vertices in full graph */
2711   int *vwgts = NULL;                      /* weights for all vertices */
2712   float *ewgts = NULL;                    /* weights for all edges */
2713   float *x = NULL, *y = NULL, *z = NULL;  /* coordinates for inertial method */
2714   char *outassignname = NULL;             /*  name of assignment output file */
2715   char *outfilename = NULL;               /* output file name */
2716   int architecture = 1;                   /* 0 => hypercube, d => d-dimensional mesh */
2717   int ndims_tot = 0;                      /* total number of cube dimensions to divide */
2718   int mesh_dims[3];                       /* dimensions of mesh of processors */
2719   double *goal = NULL;                    /* desired set sizes for each set */
2720   int global_method = 1;                  /* global partitioning algorithm */
2721   int local_method = 1;                   /* local partitioning algorithm */
2722   int rqi_flag = 0;                       /* should I use RQI/Symmlq eigensolver? */
2723   int vmax = 200;                         /* how many vertices to coarsen down to? */
2724   int ndims = 1;                          /* number of eigenvectors (2^d sets) */
2725   double eigtol = 0.001;                  /* tolerance on eigenvectors */
2726   long seed = 123636512;                  /* for random graph mutations */
2727   short int *assignment;                  /* Output partition */
2728   int fd_stdout, fd_pipe[2];
2729   PetscInt      *points;
2730   PetscMPIInt    commSize;
2731   int            i, v, p;
2732   PetscErrorCode ierr;
2733 
2734   PetscFunctionBegin;
2735   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2736   if (!numVertices) {
2737     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2738     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2739     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2740     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2741     PetscFunctionReturn(0);
2742   }
2743   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2744   for (i = 0; i < start[numVertices]; ++i) {
2745     ++adjacency[i];
2746   }
2747   if (global_method == INERTIAL_METHOD) {
2748     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2749     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2750   }
2751   mesh_dims[0] = commSize;
2752   mesh_dims[1] = 1;
2753   mesh_dims[2] = 1;
2754   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2755   /* Chaco outputs to stdout. We redirect this to a buffer. */
2756   /* TODO: check error codes for UNIX calls */
2757 #ifdef PETSC_HAVE_UNISTD_H
2758   {
2759     fd_stdout = dup(1);
2760     pipe(fd_pipe);
2761     close(1);
2762     dup2(fd_pipe[1], 1);
2763   }
2764 #endif
2765   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2766                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2767                    vmax, ndims, eigtol, seed);
2768 #ifdef PETSC_HAVE_UNISTD_H
2769   {
2770     char msgLog[10000];
2771     int  count;
2772 
2773     fflush(stdout);
2774     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2775     if (count < 0) count = 0;
2776     msgLog[count] = 0;
2777     close(1);
2778     dup2(fd_stdout, 1);
2779     close(fd_stdout);
2780     close(fd_pipe[0]);
2781     close(fd_pipe[1]);
2782     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2783   }
2784 #endif
2785   /* Convert to PetscSection+IS */
2786   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2787   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2788   for (v = 0; v < nvtxs; ++v) {
2789     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2790   }
2791   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2792   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2793   for (p = 0, i = 0; p < commSize; ++p) {
2794     for (v = 0; v < nvtxs; ++v) {
2795       if (assignment[v] == p) points[i++] = v;
2796     }
2797   }
2798   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2799   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2800   if (global_method == INERTIAL_METHOD) {
2801     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2802   }
2803   ierr = PetscFree(assignment);CHKERRQ(ierr);
2804   for (i = 0; i < start[numVertices]; ++i) {
2805     --adjacency[i];
2806   }
2807   PetscFunctionReturn(0);
2808 }
2809 #endif
2810 
2811 #ifdef PETSC_HAVE_PARMETIS
2812 #undef __FUNCT__
2813 #define __FUNCT__ "DMPlexPartition_ParMetis"
2814 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2815 {
2816   PetscFunctionBegin;
2817   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2818   PetscFunctionReturn(0);
2819 }
2820 #endif
2821 
2822 #undef __FUNCT__
2823 #define __FUNCT__ "DMPlexEnlargePartition"
2824 /* Expand the partition by BFS on the adjacency graph */
2825 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition) {
2826   PetscHashI      h;
2827   const PetscInt *points;
2828   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2829   PetscInt        pStart, pEnd, part, q;
2830   PetscErrorCode  ierr;
2831 
2832   PetscFunctionBegin;
2833   PetscHashICreate(h);
2834   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2835   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2836   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2837   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2838   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2839   for(part = pStart; part < pEnd; ++part) {
2840     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2841 
2842     PetscHashIClear(h);
2843     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2844     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2845     /* Add all existing points to h */
2846     for(p = 0; p < numPoints; ++p) {
2847       const PetscInt point = points[off+p];
2848       PetscHashIAdd(h, point, 1);
2849     }
2850     PetscHashISize(h, nP);
2851     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2852     /* Add all points in next BFS level */
2853     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2854     for(p = 0; p < numPoints; ++p) {
2855       const PetscInt point = points[off+p];
2856       PetscInt s = start[point], e = start[point+1], a;
2857 
2858       for(a = s; a < e; ++a) {
2859         PetscHashIAdd(h, adjacency[a], 1);
2860       }
2861     }
2862     PetscHashISize(h, numNewPoints);
2863     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2864     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2865     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2866     totPoints += numNewPoints;
2867   }
2868   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2869   PetscHashIDestroy(h);
2870   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2871   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2872   for(part = pStart, q = 0; part < pEnd; ++part) {
2873     PetscInt numPoints, p;
2874 
2875     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2876     for(p = 0; p < numPoints; ++p, ++q) {
2877       newPoints[q] = tmpPoints[part][p];
2878     }
2879     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2880   }
2881   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2882   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2883   PetscFunctionReturn(0);
2884 }
2885 
2886 #undef __FUNCT__
2887 #define __FUNCT__ "DMPlexCreatePartition"
2888 /*
2889   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2890 
2891   Collective on DM
2892 
2893   Input Parameters:
2894   + dm - The DM
2895   . height - The height for points in the partition
2896   - enlarge - Expand each partition with neighbors
2897 
2898   Output Parameters:
2899   + partSection - The PetscSection giving the division of points by partition
2900   . partition - The list of points by partition
2901   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2902   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2903 
2904   Level: developer
2905 
2906 .seealso DMPlexDistribute()
2907 */
2908 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition) {
2909   PetscMPIInt    size;
2910   PetscErrorCode ierr;
2911 
2912   PetscFunctionBegin;
2913   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2914   *origPartSection = PETSC_NULL;
2915   *origPartition   = PETSC_NULL;
2916   if (size == 1) {
2917     PetscInt *points;
2918     PetscInt  cStart, cEnd, c;
2919 
2920     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2921     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2922     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2923     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2924     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2925     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2926     for (c = cStart; c < cEnd; ++c) {
2927       points[c] = c;
2928     }
2929     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2930     PetscFunctionReturn(0);
2931   }
2932   if (height == 0) {
2933     PetscInt  numVertices;
2934     PetscInt *start     = PETSC_NULL;
2935     PetscInt *adjacency = PETSC_NULL;
2936 
2937     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2938     if (1) {
2939 #ifdef PETSC_HAVE_CHACO
2940       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2941 #endif
2942     } else {
2943 #ifdef PETSC_HAVE_PARMETIS
2944       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2945 #endif
2946     }
2947     if (enlarge) {
2948       *origPartSection = *partSection;
2949       *origPartition   = *partition;
2950       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2951     }
2952     ierr = PetscFree(start);CHKERRQ(ierr);
2953     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2954 # if 0
2955   } else if (height == 1) {
2956     /* Build the dual graph for faces and partition the hypergraph */
2957     PetscInt numEdges;
2958 
2959     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2960     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2961     destroyCSR(numEdges, start, adjacency);
2962 #endif
2963   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2964   PetscFunctionReturn(0);
2965 }
2966 
2967 #undef __FUNCT__
2968 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2969 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition) {
2970   /* const PetscInt  height = 0; */
2971   const PetscInt *partArray;
2972   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2973   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2974   PetscErrorCode  ierr;
2975 
2976   PetscFunctionBegin;
2977   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2978   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2979   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2980   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2981   for (rank = rStart; rank < rEnd; ++rank) {
2982     PetscInt partSize = 0;
2983     PetscInt numPoints, offset, p;
2984 
2985     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2986     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2987     for (p = 0; p < numPoints; ++p) {
2988       PetscInt  point   = partArray[offset+p], closureSize, c;
2989       PetscInt *closure = PETSC_NULL;
2990 
2991       /* TODO Include support for height > 0 case */
2992       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2993       /* Merge into existing points */
2994       if (partSize+closureSize > maxPartSize) {
2995         PetscInt *tmpPoints;
2996 
2997         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2998         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2999         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3000         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3001         partPoints = tmpPoints;
3002       }
3003       for (c = 0; c < closureSize; ++c) {
3004         partPoints[partSize+c] = closure[c*2];
3005       }
3006       partSize += closureSize;
3007       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3008       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3009     }
3010     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3011   }
3012   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3013   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3014   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3015 
3016   for (rank = rStart; rank < rEnd; ++rank) {
3017     PetscInt partSize = 0, newOffset;
3018     PetscInt numPoints, offset, p;
3019 
3020     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3021     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3022     for (p = 0; p < numPoints; ++p) {
3023       PetscInt  point   = partArray[offset+p], closureSize, c;
3024       PetscInt *closure = PETSC_NULL;
3025 
3026       /* TODO Include support for height > 0 case */
3027       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3028       /* Merge into existing points */
3029       for (c = 0; c < closureSize; ++c) {
3030         partPoints[partSize+c] = closure[c*2];
3031       }
3032       partSize += closureSize;
3033       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3034       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3035     }
3036     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3037     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3038   }
3039   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3040   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3041   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3042   PetscFunctionReturn(0);
3043 }
3044 
3045 #undef __FUNCT__
3046 #define __FUNCT__ "DMPlexDistributeField"
3047 /*
3048   Input Parameters:
3049 . originalSection
3050 , originalVec
3051 
3052   Output Parameters:
3053 . newSection
3054 . newVec
3055 */
3056 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3057 {
3058   PetscSF         fieldSF;
3059   PetscInt       *remoteOffsets, fieldSize;
3060   PetscScalar    *originalValues, *newValues;
3061   PetscErrorCode  ierr;
3062 
3063   PetscFunctionBegin;
3064   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3065 
3066   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3067   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3068   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3069 
3070   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3071   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3072   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3073   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3074   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3075   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3076   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3077   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3078   PetscFunctionReturn(0);
3079 }
3080 
3081 #undef __FUNCT__
3082 #define __FUNCT__ "DMPlexDistribute"
3083 /*@C
3084   DMPlexDistribute - Distributes the mesh and any associated sections.
3085 
3086   Not Collective
3087 
3088   Input Parameter:
3089 + dm  - The original DMPlex object
3090 . partitioner - The partitioning package, or NULL for the default
3091 - overlap - The overlap of partitions, 0 is the default
3092 
3093   Output Parameter:
3094 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3095 
3096   Note: If the mesh was not distributed, the return value is PETSC_NULL
3097 
3098   Level: intermediate
3099 
3100 .keywords: mesh, elements
3101 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3102 @*/
3103 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3104 {
3105   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3106   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3107   const PetscInt height = 0;
3108   PetscInt       dim, numRemoteRanks;
3109   IS             origCellPart,        cellPart,        part;
3110   PetscSection   origCellPartSection, cellPartSection, partSection;
3111   PetscSFNode   *remoteRanks;
3112   PetscSF        partSF, pointSF, coneSF;
3113   ISLocalToGlobalMapping renumbering;
3114   PetscSection   originalConeSection, newConeSection;
3115   PetscInt      *remoteOffsets;
3116   PetscInt      *cones, *newCones, newConesSize;
3117   PetscBool      flg;
3118   PetscMPIInt    rank, numProcs, p;
3119   PetscErrorCode ierr;
3120 
3121   PetscFunctionBegin;
3122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3123   PetscValidPointer(dmParallel,4);
3124   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3125   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3126   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3127   *dmParallel = PETSC_NULL;
3128   if (numProcs == 1) PetscFunctionReturn(0);
3129 
3130   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3131   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3132   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3133   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3134   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3135   if (!rank) {
3136     numRemoteRanks = numProcs;
3137   } else {
3138     numRemoteRanks = 0;
3139   }
3140   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3141   for (p = 0; p < numRemoteRanks; ++p) {
3142     remoteRanks[p].rank  = p;
3143     remoteRanks[p].index = 0;
3144   }
3145   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3146   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3147   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3148   if (flg) {
3149     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3150     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3151     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3152     if (origCellPart) {
3153       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3154       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3155       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3156     }
3157     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3158   }
3159   /* Close the partition over the mesh */
3160   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3161   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3162   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3163   /* Create new mesh */
3164   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3165   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3166   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3167   pmesh = (DM_Plex *) (*dmParallel)->data;
3168   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3169   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3170   if (flg) {
3171     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3172     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3173     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3174     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3175     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3176     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3177   }
3178   /* Distribute cone section */
3179   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3180   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3181   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3182   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3183   {
3184     PetscInt pStart, pEnd, p;
3185 
3186     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3187     for (p = pStart; p < pEnd; ++p) {
3188       PetscInt coneSize;
3189       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3190       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3191     }
3192   }
3193   /* Communicate and renumber cones */
3194   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3195   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3196   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3197   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3198   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3199   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3200   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3201   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3202   if (flg) {
3203     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3204     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3205     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3206     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3207     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3208   }
3209   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3210   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3211   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3212   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3213   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3214   /* Create supports and stratify sieve */
3215   {
3216     PetscInt pStart, pEnd;
3217 
3218     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3219     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3220   }
3221   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3222   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3223   /* Distribute Coordinates */
3224   {
3225     PetscSection originalCoordSection, newCoordSection;
3226     Vec          originalCoordinates, newCoordinates;
3227     const char  *name;
3228 
3229     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3230     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3231     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3232     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3233     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3234     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3235 
3236     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3237     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3238     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3239   }
3240   /* Distribute labels */
3241   {
3242     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3243     PetscInt   numLabels = 0, l;
3244 
3245     /* Bcast number of labels */
3246     while(next) {++numLabels; next = next->next;}
3247     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3248     next = mesh->labels;
3249     for (l = 0; l < numLabels; ++l) {
3250       DMLabel         newLabel;
3251       const PetscInt *partArray;
3252       char           *name;
3253       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3254       PetscMPIInt    *sendcnts = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3255       PetscInt        nameSize, s, p;
3256       PetscBool       isdepth;
3257       size_t          len = 0;
3258 
3259       /* Bcast name (could filter for no points) */
3260       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3261       nameSize = len;
3262       ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3263       ierr = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3264       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3265       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3266       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3267       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3268       ierr = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3269       newLabel->name = name;
3270       /* Bcast numStrata (could filter for no points in stratum) */
3271       if (!rank) {newLabel->numStrata = next->numStrata;}
3272       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3273       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3274                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3275                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3276       /* Bcast stratumValues (could filter for no points in stratum) */
3277       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3278       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3279       /* Find size on each process and Scatter */
3280       if (!rank) {
3281         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3282         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3283         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3284         for (s = 0; s < next->numStrata; ++s) {
3285           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3286             const PetscInt point = next->points[p];
3287             PetscInt       proc;
3288 
3289             for (proc = 0; proc < numProcs; ++proc) {
3290               PetscInt dof, off, pPart;
3291 
3292               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3293               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3294               for (pPart = off; pPart < off+dof; ++pPart) {
3295                 if (partArray[pPart] == point) {
3296                   ++stratumSizes[proc*next->numStrata+s];
3297                   break;
3298                 }
3299               }
3300             }
3301           }
3302         }
3303         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3304       }
3305       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3306       /* Calculate stratumOffsets */
3307       newLabel->stratumOffsets[0] = 0;
3308       for (s = 0; s < newLabel->numStrata; ++s) {
3309         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3310       }
3311       /* Pack points and Scatter */
3312       if (!rank) {
3313         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3314         displs[0] = 0;
3315         for (p = 0; p < numProcs; ++p) {
3316           sendcnts[p] = 0;
3317           for (s = 0; s < next->numStrata; ++s) {
3318             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3319           }
3320           offsets[p]  = displs[p];
3321           displs[p+1] = displs[p] + sendcnts[p];
3322         }
3323         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3324         for (s = 0; s < next->numStrata; ++s) {
3325           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3326             const PetscInt point = next->points[p];
3327             PetscInt       proc;
3328 
3329             for (proc = 0; proc < numProcs; ++proc) {
3330               PetscInt dof, off, pPart;
3331 
3332               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3333               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3334               for (pPart = off; pPart < off+dof; ++pPart) {
3335                 if (partArray[pPart] == point) {
3336                   points[offsets[proc]++] = point;
3337                   break;
3338                 }
3339               }
3340             }
3341           }
3342         }
3343       }
3344       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3345       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3346       ierr = PetscFree(points);CHKERRQ(ierr);
3347       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3348       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3349       /* Renumber points */
3350       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3351       /* Sort points */
3352       for (s = 0; s < newLabel->numStrata; ++s) {
3353         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3354       }
3355       /* Insert into list */
3356       if (newNext) {
3357         newNext->next = newLabel;
3358       } else {
3359         pmesh->labels = newLabel;
3360       }
3361       newNext = newLabel;
3362       if (!rank) {next = next->next;}
3363     }
3364   }
3365   /* Cleanup Partition */
3366   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3367   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3368   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3369   ierr = ISDestroy(&part);CHKERRQ(ierr);
3370   /* Create point SF for parallel mesh */
3371   {
3372     const PetscInt *leaves;
3373     PetscSFNode    *remotePoints, *rowners, *lowners;
3374     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3375     PetscInt        pStart, pEnd;
3376 
3377     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3378     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3379     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3380     for (p=0; p<numRoots; p++) {
3381       rowners[p].rank = -1;
3382       rowners[p].index = -1;
3383     }
3384     if (origCellPart) {
3385       /* Make sure cells in the original partition are not assigned to other procs */
3386       const PetscInt *origCells;
3387 
3388       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3389       for (p = 0; p < numProcs; ++p) {
3390         PetscInt dof, off, d;
3391 
3392         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3393         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3394         for(d = off; d < off+dof; ++d) {
3395           rowners[origCells[d]].rank = p;
3396         }
3397       }
3398       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3399     }
3400     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3401     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3402 
3403     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3404     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3405     for (p = 0; p < numLeaves; ++p) {
3406       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3407         lowners[p].rank = rank;
3408         lowners[p].index = leaves ? leaves[p] : p;
3409       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3410         lowners[p].rank = -2;
3411         lowners[p].index = -2;
3412       }
3413     }
3414     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3415       rowners[p].rank = -3;
3416       rowners[p].index = -3;
3417     }
3418     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3419     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3420     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3421     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3422     for (p = 0; p < numLeaves; ++p) {
3423       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3424       if (lowners[p].rank != rank) ++numGhostPoints;
3425     }
3426     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3427     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3428     for (p = 0, gp = 0; p < numLeaves; ++p) {
3429       if (lowners[p].rank != rank) {
3430         ghostPoints[gp]       = leaves ? leaves[p] : p;
3431         remotePoints[gp].rank  = lowners[p].rank;
3432         remotePoints[gp].index = lowners[p].index;
3433         ++gp;
3434       }
3435     }
3436     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3437     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3438     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3439   }
3440   /* Cleanup */
3441   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3442   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3443   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3444   PetscFunctionReturn(0);
3445 }
3446 
3447 #undef __FUNCT__
3448 #define __FUNCT__ "DMPlexRenumber_Private"
3449 /*
3450   Reasons to renumber:
3451 
3452   1) Permute points, e.g. bandwidth reduction (Renumber)
3453 
3454     a) Must not mix strata
3455 
3456   2) Shift numbers for point insertion (Shift)
3457 
3458     a) Want operation brken into parts so that insertion can be interleaved
3459 
3460   renumbering - An IS which provides the new numbering
3461 */
3462 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3463 {
3464   PetscFunctionBegin;
3465   PetscFunctionReturn(0);
3466 }
3467 
3468 #undef __FUNCT__
3469 #define __FUNCT__ "DMPlexShiftPoint_Private"
3470 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3471 {
3472   if (depth < 0) return p;
3473   /* Cells    */ if (p < depthEnd[depth])   return p;
3474   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3475   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3476   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3477 }
3478 
3479 #undef __FUNCT__
3480 #define __FUNCT__ "DMPlexShiftSizes_Private"
3481 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3482 {
3483   PetscInt      *depthEnd;
3484   PetscInt       depth = 0, d, pStart, pEnd, p;
3485   PetscErrorCode ierr;
3486 
3487   PetscFunctionBegin;
3488   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3489   if (depth < 0) PetscFunctionReturn(0);
3490   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3491   /* Step 1: Expand chart */
3492   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3493   for(d = 0; d <= depth; ++d) {
3494     pEnd += depthShift[d];
3495     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3496   }
3497   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3498   /* Step 2: Set cone and support sizes */
3499   for(d = 0; d <= depth; ++d) {
3500     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3501     for(p = pStart; p < pEnd; ++p) {
3502       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3503       PetscInt size;
3504 
3505       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3506       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3507       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3508       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3509     }
3510   }
3511   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3512   PetscFunctionReturn(0);
3513 }
3514 
3515 #undef __FUNCT__
3516 #define __FUNCT__ "DMPlexShiftPoints_Private"
3517 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3518 {
3519   PetscInt      *depthEnd, *newpoints;
3520   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3521   PetscErrorCode ierr;
3522 
3523   PetscFunctionBegin;
3524   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3525   if (depth < 0) PetscFunctionReturn(0);
3526   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3527   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3528   for(d = 0; d <= depth; ++d) {
3529     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3530   }
3531   /* Step 5: Set cones and supports */
3532   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3533   for(p = pStart; p < pEnd; ++p) {
3534     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3535     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3536 
3537     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3538     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3539     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3540     for(i = 0; i < size; ++i) {
3541       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3542     }
3543     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3544     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3545     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3546     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3547     for(i = 0; i < size; ++i) {
3548       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3549     }
3550     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3551   }
3552   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3553   PetscFunctionReturn(0);
3554 }
3555 
3556 #undef __FUNCT__
3557 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3558 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3559 {
3560   PetscSection   coordSection, newCoordSection;
3561   Vec            coordinates;
3562   PetscInt      *depthEnd;
3563   PetscInt       dim, depth = 0, d, vStart, vEnd, v;
3564   PetscErrorCode ierr;
3565 
3566   PetscFunctionBegin;
3567   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3568   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3569   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3570   for(d = 0; d <= depth; ++d) {
3571     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3572   }
3573   /* Step 8: Convert coordinates */
3574   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3575   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3576   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3577   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3578   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3579   ierr = PetscSectionSetChart(newCoordSection, DMPlexShiftPoint_Private(vStart, depth, depthEnd, depthShift), DMPlexShiftPoint_Private(vEnd, depth, depthEnd, depthShift));CHKERRQ(ierr);
3580   for(v = vStart; v < vEnd; ++v) {
3581     const PetscInt newv = DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift);
3582     ierr = PetscSectionSetDof(newCoordSection, newv, dim);CHKERRQ(ierr);
3583     ierr = PetscSectionSetFieldDof(newCoordSection, newv, 0, dim);CHKERRQ(ierr);
3584   }
3585   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3586   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3587   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3588   ierr = DMSetCoordinatesLocal(dmNew, coordinates);CHKERRQ(ierr);
3589   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3590   PetscFunctionReturn(0);
3591 }
3592 
3593 #undef __FUNCT__
3594 #define __FUNCT__ "DMPlexShiftSF_Private"
3595 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3596 {
3597   PetscInt          *depthEnd;
3598   PetscInt           depth = 0, d;
3599   PetscSF            sfPoint, sfPointNew;
3600   const PetscSFNode *remotePoints;
3601   PetscSFNode       *gremotePoints;
3602   const PetscInt    *localPoints;
3603   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3604   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3605   PetscMPIInt        numProcs;
3606   PetscErrorCode     ierr;
3607 
3608   PetscFunctionBegin;
3609   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3610   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3611   for(d = 0; d <= depth; ++d) {
3612     totShift += depthShift[d];
3613     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3614   }
3615   /* Step 9: Convert pointSF */
3616   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3617   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3618   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3619   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3620   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3621   if (numRoots >= 0) {
3622     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3623     for(l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3624     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3625     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3626     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3627     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3628     for(l = 0; l < numLeaves; ++l) {
3629       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3630       gremotePoints[l].rank  = remotePoints[l].rank;
3631       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3632     }
3633     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3634     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3635   }
3636   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3637   PetscFunctionReturn(0);
3638 }
3639 
3640 #undef __FUNCT__
3641 #define __FUNCT__ "DMPlexShiftLabels_Private"
3642 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3643 {
3644   PetscSF        sfPoint;
3645   DMLabel        vtkLabel, ghostLabel;
3646   PetscInt      *depthEnd;
3647   const PetscSFNode *leafRemote;
3648   const PetscInt    *leafLocal;
3649   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3650   PetscMPIInt    rank;
3651   PetscErrorCode ierr;
3652 
3653   PetscFunctionBegin;
3654   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3655   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3656   for(d = 0; d <= depth; ++d) {
3657     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3658   }
3659   /* Step 10: Convert labels */
3660   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3661   for(l = 0; l < numLabels; ++l) {
3662     DMLabel         label, newlabel;
3663     const char     *lname;
3664     PetscBool       isDepth;
3665     IS              valueIS;
3666     const PetscInt *values;
3667     PetscInt        numValues, val;
3668 
3669     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3670     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3671     if (isDepth) continue;
3672     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3673     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3674     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3675     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3676     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3677     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3678     for(val = 0; val < numValues; ++val) {
3679       IS              pointIS;
3680       const PetscInt *points;
3681       PetscInt        numPoints, p;
3682 
3683       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3684       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3685       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3686       for(p = 0; p < numPoints; ++p) {
3687         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3688 
3689         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3690       }
3691       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3692       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3693     }
3694     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3695     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3696   }
3697   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3698   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3699   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3700   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3701   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3702   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3703   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3704   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3705   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3706   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3707   for(l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3708     for(; c < leafLocal[l] && c < cEnd; ++c) {
3709       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3710     }
3711     if (leafLocal[l] >= cEnd) break;
3712     if (leafRemote[l].rank == rank) {
3713       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3714     } else {
3715       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3716     }
3717   }
3718   for(; c < cEnd; ++c) {
3719     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3720   }
3721   if (0) {
3722     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3723     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3724     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3725   }
3726   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3727   for(f = fStart; f < fEnd; ++f) {
3728     PetscInt numCells;
3729 
3730     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3731     if (numCells < 2) {
3732       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3733     } else {
3734       const PetscInt *cells = PETSC_NULL;
3735       PetscInt        vA, vB;
3736 
3737       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3738       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3739       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3740       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3741     }
3742   }
3743   if (0) {
3744     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3745     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3746     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3747   }
3748   PetscFunctionReturn(0);
3749 }
3750 
3751 #undef __FUNCT__
3752 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3753 /*@C
3754   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3755 
3756   Collective on dm
3757 
3758   Input Parameters:
3759 + dm - The original DM
3760 - labelName - The label specifying the boundary faces (this could be auto-generated)
3761 
3762   Output Parameters:
3763 + numGhostCells - The number of ghost cells added to the DM
3764 - dmGhosted - The new DM
3765 
3766   Level: developer
3767 
3768 .seealso: DMCreate()
3769 */
3770 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3771 {
3772   DMLabel         label;
3773   IS              valueIS;
3774   const PetscInt *values;
3775   PetscInt       *depthShift;
3776   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3777   PetscErrorCode  ierr;
3778 
3779   PetscFunctionBegin;
3780   /* Count ghost cells */
3781   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3782   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3783   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3784   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3785   *numGhostCells = 0;
3786   for(fs = 0; fs < numFS; ++fs) {
3787     PetscInt numBdFaces;
3788 
3789     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3790     *numGhostCells += numBdFaces;
3791   }
3792   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3793   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3794   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3795   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3796   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3797   /* Step 3: Set cone/support sizes for new points */
3798   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3799   for(c = cEnd; c < cEnd + *numGhostCells; ++c) {
3800     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3801   }
3802   for(fs = 0; fs < numFS; ++fs) {
3803     IS              faceIS;
3804     const PetscInt *faces;
3805     PetscInt        numFaces, f;
3806 
3807     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3808     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3809     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3810     for(f = 0; f < numFaces; ++f) {
3811       PetscInt size;
3812 
3813       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3814       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3815       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3816     }
3817     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3818     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3819   }
3820   /* Step 4: Setup ghosted DM */
3821   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3822   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3823   /* Step 6: Set cones and supports for new points */
3824   ghostCell = cEnd;
3825   for(fs = 0; fs < numFS; ++fs) {
3826     IS              faceIS;
3827     const PetscInt *faces;
3828     PetscInt        numFaces, f;
3829 
3830     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3831     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3832     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3833     for(f = 0; f < numFaces; ++f, ++ghostCell) {
3834       PetscInt newFace = faces[f] + *numGhostCells;
3835 
3836       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3837       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3838     }
3839     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3840     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3841   }
3842   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3843   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3844   /* Step 7: Stratify */
3845   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3846   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3847   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3848   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3849   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3850   PetscFunctionReturn(0);
3851 }
3852 
3853 #undef __FUNCT__
3854 #define __FUNCT__ "DMPlexConstructGhostCells"
3855 /*@C
3856   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3857 
3858   Collective on dm
3859 
3860   Input Parameters:
3861 + dm - The original DM
3862 - labelName - The label specifying the boundary faces (this could be auto-generated)
3863 
3864   Output Parameters:
3865 + numGhostCells - The number of ghost cells added to the DM
3866 - dmGhosted - The new DM
3867 
3868   Level: developer
3869 
3870 .seealso: DMCreate()
3871 */
3872 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3873 {
3874   DM             gdm;
3875   PetscInt       dim;
3876   PetscErrorCode ierr;
3877 
3878   PetscFunctionBegin;
3879   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3880   PetscValidPointer(numGhostCells, 3);
3881   PetscValidPointer(dmGhosted, 4);
3882   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3883   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3884   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3885   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3886   switch(dim) {
3887   case 2:
3888     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3889     break;
3890   default:
3891     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3892   }
3893   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3894   *dmGhosted = gdm;
3895   PetscFunctionReturn(0);
3896 }
3897 
3898 #undef __FUNCT__
3899 #define __FUNCT__ "DMPlexInterpolate_2D"
3900 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
3901 {
3902   DM             idm;
3903   DM_Plex    *mesh;
3904   PetscHashIJ    edgeTable;
3905   PetscInt      *off;
3906   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
3907   PetscInt       numEdges, firstEdge, edge, e;
3908   PetscErrorCode ierr;
3909 
3910   PetscFunctionBegin;
3911   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3912   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3913   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3914   numCells    = cEnd - cStart;
3915   numVertices = vEnd - vStart;
3916   firstEdge   = numCells + numVertices;
3917   numEdges    = 0 ;
3918   /* Count edges using algorithm from CreateNeighborCSR */
3919   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
3920   if (off) {
3921     PetscInt numCorners = 0;
3922 
3923     numEdges = off[numCells]/2;
3924 #if 0
3925     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
3926     numEdges += 3*numCells - off[numCells];
3927 #else
3928     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
3929     for(c = cStart; c < cEnd; ++c) {
3930       PetscInt coneSize;
3931 
3932       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
3933       numCorners += coneSize;
3934     }
3935     numEdges += numCorners - off[numCells];
3936 #endif
3937   }
3938 #if 0
3939   /* Check Euler characteristic V - E + F = 1 */
3940   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
3941 #endif
3942   /* Create interpolated mesh */
3943   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
3944   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
3945   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
3946   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
3947   for (c = 0; c < numCells; ++c) {
3948     PetscInt numCorners;
3949 
3950     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
3951     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
3952   }
3953   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
3954     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
3955   }
3956   ierr = DMSetUp(idm);CHKERRQ(ierr);
3957   /* Get edge cones from subsets of cell vertices */
3958   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
3959   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
3960 
3961   for (c = 0, edge = firstEdge; c < numCells; ++c) {
3962     const PetscInt *cellFaces;
3963     PetscInt        numCellFaces, faceSize, cf;
3964 
3965     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
3966     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
3967     for (cf = 0; cf < numCellFaces; ++cf) {
3968 #if 1
3969       PetscHashIJKey key = {PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]),
3970                             PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1])};
3971 
3972       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
3973       if (e < 0) {
3974         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
3975         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
3976         e    = edge++;
3977       }
3978 #else
3979       PetscBool found = PETSC_FALSE;
3980 
3981       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
3982       for (e = firstEdge; e < edge; ++e) {
3983         const PetscInt *cone;
3984 
3985         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
3986         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
3987             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
3988           found = PETSC_TRUE;
3989           break;
3990         }
3991       }
3992       if (!found) {
3993         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
3994         ++edge;
3995       }
3996 #endif
3997       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
3998     }
3999   }
4000   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4001   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4002   ierr = PetscFree(off);CHKERRQ(ierr);
4003   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4004   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4005   mesh = (DM_Plex *) (idm)->data;
4006   /* Orient edges */
4007   for (c = 0; c < numCells; ++c) {
4008     const PetscInt *cone = PETSC_NULL, *cellFaces;
4009     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4010 
4011     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4012     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4013     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4014     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4015     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4016     for (cf = 0; cf < numCellFaces; ++cf) {
4017       const PetscInt *econe = PETSC_NULL;
4018       PetscInt        esize;
4019 
4020       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4021       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4022       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]);
4023       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4024         /* Correctly oriented */
4025         mesh->coneOrientations[coff+cf] = 0;
4026       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4027         /* Start at index 1, and reverse orientation */
4028         mesh->coneOrientations[coff+cf] = -(1+1);
4029       }
4030     }
4031   }
4032   *dmInt  = idm;
4033   PetscFunctionReturn(0);
4034 }
4035 
4036 #undef __FUNCT__
4037 #define __FUNCT__ "DMPlexInterpolate_3D"
4038 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4039 {
4040   DM             idm, fdm;
4041   DM_Plex    *mesh;
4042   PetscInt      *off;
4043   const PetscInt numCorners = 4;
4044   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4045   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4046   PetscErrorCode ierr;
4047 
4048   PetscFunctionBegin;
4049   {
4050     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4051     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4052     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4053   }
4054   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4055   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4056   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4057   numCells    = cEnd - cStart;
4058   numVertices = vEnd - vStart;
4059   firstFace   = numCells + numVertices;
4060   numFaces    = 0 ;
4061   /* Count faces using algorithm from CreateNeighborCSR */
4062   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4063   if (off) {
4064     numFaces = off[numCells]/2;
4065     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4066     numFaces += 4*numCells - off[numCells];
4067   }
4068   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4069   firstEdge = firstFace + numFaces;
4070   numEdges  = numVertices + numFaces - numCells - 1;
4071   /* Create interpolated mesh */
4072   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4073   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4074   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4075   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4076   for (c = 0; c < numCells; ++c) {
4077     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4078   }
4079   for (f = firstFace; f < firstFace+numFaces; ++f) {
4080     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4081   }
4082   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4083     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4084   }
4085   ierr = DMSetUp(idm);CHKERRQ(ierr);
4086   /* Get face cones from subsets of cell vertices */
4087   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4088   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4089   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4090   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4091   for (f = firstFace; f < firstFace+numFaces; ++f) {
4092     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4093   }
4094   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4095   for (c = 0, face = firstFace; c < numCells; ++c) {
4096     const PetscInt *cellFaces;
4097     PetscInt        numCellFaces, faceSize, cf;
4098 
4099     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4100     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4101     for (cf = 0; cf < numCellFaces; ++cf) {
4102       PetscBool found = PETSC_FALSE;
4103 
4104       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4105       for (f = firstFace; f < face; ++f) {
4106         const PetscInt *cone = PETSC_NULL;
4107 
4108         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4109         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4110             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4111             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4112             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4113             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4114             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4115           found = PETSC_TRUE;
4116           break;
4117         }
4118       }
4119       if (!found) {
4120         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4121         /* Save the vertices for orientation calculation */
4122         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4123         ++face;
4124       }
4125       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4126     }
4127   }
4128   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4129   /* Get edge cones from subsets of face vertices */
4130   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4131     const PetscInt *cellFaces;
4132     PetscInt        numCellFaces, faceSize, cf;
4133 
4134     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4135     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4136     for (cf = 0; cf < numCellFaces; ++cf) {
4137       PetscBool found = PETSC_FALSE;
4138 
4139       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4140       for (e = firstEdge; e < edge; ++e) {
4141         const PetscInt *cone = PETSC_NULL;
4142 
4143         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4144         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4145             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4146           found = PETSC_TRUE;
4147           break;
4148         }
4149       }
4150       if (!found) {
4151         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4152         ++edge;
4153       }
4154       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4155     }
4156   }
4157   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4158   ierr = PetscFree(off);CHKERRQ(ierr);
4159   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4160   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4161   mesh = (DM_Plex *) (idm)->data;
4162   /* Orient edges */
4163   for (f = firstFace; f < firstFace+numFaces; ++f) {
4164     const PetscInt *cone, *cellFaces;
4165     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4166 
4167     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4168     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4169     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4170     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4171     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4172     for (cf = 0; cf < numCellFaces; ++cf) {
4173       const PetscInt *econe;
4174       PetscInt        esize;
4175 
4176       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4177       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4178       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]);
4179       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4180         /* Correctly oriented */
4181         mesh->coneOrientations[coff+cf] = 0;
4182       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4183         /* Start at index 1, and reverse orientation */
4184         mesh->coneOrientations[coff+cf] = -(1+1);
4185       }
4186     }
4187   }
4188   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4189   /* Orient faces */
4190   for (c = 0; c < numCells; ++c) {
4191     const PetscInt *cone, *cellFaces;
4192     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4193 
4194     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4195     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4196     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4197     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4198     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4199     for (cf = 0; cf < numCellFaces; ++cf) {
4200       PetscInt *origClosure = PETSC_NULL, *closure;
4201       PetscInt  closureSize, i;
4202 
4203       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4204       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4205       for (i = 4; i < 7; ++i) {
4206         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);
4207       }
4208       closure = &origClosure[4*2];
4209       /* Remember that this is the orientation for edges, not vertices */
4210       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4211         /* Correctly oriented */
4212         mesh->coneOrientations[coff+cf] = 0;
4213       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4214         /* Shifted by 1 */
4215         mesh->coneOrientations[coff+cf] = 1;
4216       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4217         /* Shifted by 2 */
4218         mesh->coneOrientations[coff+cf] = 2;
4219       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4220         /* Start at edge 1, and reverse orientation */
4221         mesh->coneOrientations[coff+cf] = -(1+1);
4222       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4223         /* Start at index 0, and reverse orientation */
4224         mesh->coneOrientations[coff+cf] = -(0+1);
4225       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4226         /* Start at index 2, and reverse orientation */
4227         mesh->coneOrientations[coff+cf] = -(2+1);
4228       } 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);
4229       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4230     }
4231   }
4232   {
4233     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4234     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4235     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4236   }
4237   *dmInt  = idm;
4238   PetscFunctionReturn(0);
4239 }
4240 
4241 #undef __FUNCT__
4242 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4243 /*
4244   This takes as input the common mesh generator output, a list of the vertices for each cell
4245 */
4246 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4247 {
4248   PetscInt      *cone, c, p;
4249   PetscErrorCode ierr;
4250 
4251   PetscFunctionBegin;
4252   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4253   for (c = 0; c < numCells; ++c) {
4254     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4255   }
4256   ierr = DMSetUp(dm);CHKERRQ(ierr);
4257   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4258   for (c = 0; c < numCells; ++c) {
4259     for (p = 0; p < numCorners; ++p) {
4260       cone[p] = cells[c*numCorners+p]+numCells;
4261     }
4262     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4263   }
4264   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4265   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4266   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4267   PetscFunctionReturn(0);
4268 }
4269 
4270 #undef __FUNCT__
4271 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4272 /*
4273   This takes as input the coordinates for each vertex
4274 */
4275 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4276 {
4277   PetscSection   coordSection;
4278   Vec            coordinates;
4279   PetscScalar   *coords;
4280   PetscInt       coordSize, v, d;
4281   PetscErrorCode ierr;
4282 
4283   PetscFunctionBegin;
4284   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4285   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4286   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4287   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4288   for (v = numCells; v < numCells+numVertices; ++v) {
4289     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4290     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4291   }
4292   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4293   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4294   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4295   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4296   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4297   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4298   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4299   for (v = 0; v < numVertices; ++v) {
4300     for (d = 0; d < spaceDim; ++d) {
4301       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4302     }
4303   }
4304   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4305   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4306   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4307   PetscFunctionReturn(0);
4308 }
4309 
4310 #undef __FUNCT__
4311 #define __FUNCT__ "DMPlexCreateFromCellList"
4312 /*
4313   This takes as input the common mesh generator output, a list of the vertices for each cell
4314 */
4315 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4316 {
4317   PetscErrorCode ierr;
4318 
4319   PetscFunctionBegin;
4320   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4321   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4322   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4323   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4324   if (interpolate) {
4325     DM idm;
4326 
4327     switch(dim) {
4328     case 2:
4329       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4330     case 3:
4331       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4332     default:
4333       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4334     }
4335     ierr = DMDestroy(dm);CHKERRQ(ierr);
4336     *dm  = idm;
4337   }
4338   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4339   PetscFunctionReturn(0);
4340 }
4341 
4342 #ifdef PETSC_HAVE_TRIANGLE
4343 #include <triangle.h>
4344 
4345 #undef __FUNCT__
4346 #define __FUNCT__ "InitInput_Triangle"
4347 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx) {
4348   PetscFunctionBegin;
4349   inputCtx->numberofpoints = 0;
4350   inputCtx->numberofpointattributes = 0;
4351   inputCtx->pointlist = PETSC_NULL;
4352   inputCtx->pointattributelist = PETSC_NULL;
4353   inputCtx->pointmarkerlist = PETSC_NULL;
4354   inputCtx->numberofsegments = 0;
4355   inputCtx->segmentlist = PETSC_NULL;
4356   inputCtx->segmentmarkerlist = PETSC_NULL;
4357   inputCtx->numberoftriangleattributes = 0;
4358   inputCtx->trianglelist = PETSC_NULL;
4359   inputCtx->numberofholes = 0;
4360   inputCtx->holelist = PETSC_NULL;
4361   inputCtx->numberofregions = 0;
4362   inputCtx->regionlist = PETSC_NULL;
4363   PetscFunctionReturn(0);
4364 }
4365 
4366 #undef __FUNCT__
4367 #define __FUNCT__ "InitOutput_Triangle"
4368 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx) {
4369   PetscFunctionBegin;
4370   outputCtx->numberofpoints = 0;
4371   outputCtx->pointlist = PETSC_NULL;
4372   outputCtx->pointattributelist = PETSC_NULL;
4373   outputCtx->pointmarkerlist = PETSC_NULL;
4374   outputCtx->numberoftriangles = 0;
4375   outputCtx->trianglelist = PETSC_NULL;
4376   outputCtx->triangleattributelist = PETSC_NULL;
4377   outputCtx->neighborlist = PETSC_NULL;
4378   outputCtx->segmentlist = PETSC_NULL;
4379   outputCtx->segmentmarkerlist = PETSC_NULL;
4380   outputCtx->numberofedges = 0;
4381   outputCtx->edgelist = PETSC_NULL;
4382   outputCtx->edgemarkerlist = PETSC_NULL;
4383   PetscFunctionReturn(0);
4384 }
4385 
4386 #undef __FUNCT__
4387 #define __FUNCT__ "FiniOutput_Triangle"
4388 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx) {
4389   PetscFunctionBegin;
4390   free(outputCtx->pointmarkerlist);
4391   free(outputCtx->edgelist);
4392   free(outputCtx->edgemarkerlist);
4393   free(outputCtx->trianglelist);
4394   free(outputCtx->neighborlist);
4395   PetscFunctionReturn(0);
4396 }
4397 
4398 #undef __FUNCT__
4399 #define __FUNCT__ "DMPlexGenerate_Triangle"
4400 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4401 {
4402   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4403   PetscInt             dim              = 2;
4404   const PetscBool      createConvexHull = PETSC_FALSE;
4405   const PetscBool      constrained      = PETSC_FALSE;
4406   struct triangulateio in;
4407   struct triangulateio out;
4408   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4409   PetscMPIInt          rank;
4410   PetscErrorCode       ierr;
4411 
4412   PetscFunctionBegin;
4413   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4414   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4415   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4416   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4417   in.numberofpoints = vEnd - vStart;
4418   if (in.numberofpoints > 0) {
4419     PetscSection coordSection;
4420     Vec          coordinates;
4421     PetscScalar *array;
4422 
4423     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4424     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4425     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4426     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4427     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4428     for (v = vStart; v < vEnd; ++v) {
4429       const PetscInt idx = v - vStart;
4430       PetscInt       off, d;
4431 
4432       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4433       for (d = 0; d < dim; ++d) {
4434         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4435       }
4436       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4437     }
4438     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4439   }
4440   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4441   in.numberofsegments = eEnd - eStart;
4442   if (in.numberofsegments > 0) {
4443     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4444     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4445     for (e = eStart; e < eEnd; ++e) {
4446       const PetscInt  idx = e - eStart;
4447       const PetscInt *cone;
4448 
4449       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4450       in.segmentlist[idx*2+0] = cone[0] - vStart;
4451       in.segmentlist[idx*2+1] = cone[1] - vStart;
4452       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4453     }
4454   }
4455 #if 0 /* Do not currently support holes */
4456   PetscReal *holeCoords;
4457   PetscInt   h, d;
4458 
4459   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4460   if (in.numberofholes > 0) {
4461     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4462     for (h = 0; h < in.numberofholes; ++h) {
4463       for (d = 0; d < dim; ++d) {
4464         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4465       }
4466     }
4467   }
4468 #endif
4469   if (!rank) {
4470     char args[32];
4471 
4472     /* Take away 'Q' for verbose output */
4473     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4474     if (createConvexHull) {
4475       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4476     }
4477     if (constrained) {
4478       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4479     }
4480     triangulate(args, &in, &out, PETSC_NULL);
4481   }
4482   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4483   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4484   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4485   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4486   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4487 
4488   {
4489     const PetscInt numCorners  = 3;
4490     const PetscInt numCells    = out.numberoftriangles;
4491     const PetscInt numVertices = out.numberofpoints;
4492     const int     *cells       = out.trianglelist;
4493     const double  *meshCoords  = out.pointlist;
4494 
4495     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4496     /* Set labels */
4497     for (v = 0; v < numVertices; ++v) {
4498       if (out.pointmarkerlist[v]) {
4499         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4500       }
4501     }
4502     if (interpolate) {
4503       for (e = 0; e < out.numberofedges; e++) {
4504         if (out.edgemarkerlist[e]) {
4505           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4506           const PetscInt *edges;
4507           PetscInt        numEdges;
4508 
4509           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4510           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4511           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4512           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4513         }
4514       }
4515     }
4516     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4517   }
4518 #if 0 /* Do not currently support holes */
4519   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4520 #endif
4521   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4522   PetscFunctionReturn(0);
4523 }
4524 
4525 #undef __FUNCT__
4526 #define __FUNCT__ "DMPlexRefine_Triangle"
4527 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4528 {
4529   MPI_Comm             comm = ((PetscObject) dm)->comm;
4530   PetscInt             dim  = 2;
4531   struct triangulateio in;
4532   struct triangulateio out;
4533   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4534   PetscMPIInt          rank;
4535   PetscErrorCode       ierr;
4536 
4537   PetscFunctionBegin;
4538   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4539   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4540   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4541   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4542   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4543   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4544   in.numberofpoints = vEnd - vStart;
4545   if (in.numberofpoints > 0) {
4546     PetscSection coordSection;
4547     Vec          coordinates;
4548     PetscScalar *array;
4549 
4550     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4551     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4552     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4553     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4554     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4555     for (v = vStart; v < vEnd; ++v) {
4556       const PetscInt idx = v - vStart;
4557       PetscInt       off, d;
4558 
4559       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4560       for (d = 0; d < dim; ++d) {
4561         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4562       }
4563       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4564     }
4565     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4566   }
4567   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4568   in.numberofcorners   = 3;
4569   in.numberoftriangles = cEnd - cStart;
4570   in.trianglearealist  = (double *) maxVolumes;
4571   if (in.numberoftriangles > 0) {
4572     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4573     for (c = cStart; c < cEnd; ++c) {
4574       const PetscInt idx     = c - cStart;
4575       PetscInt      *closure = PETSC_NULL;
4576       PetscInt       closureSize;
4577 
4578       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4579       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4580       for (v = 0; v < 3; ++v) {
4581         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4582       }
4583       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4584     }
4585   }
4586   /* TODO: Segment markers are missing on input */
4587 #if 0 /* Do not currently support holes */
4588   PetscReal *holeCoords;
4589   PetscInt   h, d;
4590 
4591   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4592   if (in.numberofholes > 0) {
4593     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4594     for (h = 0; h < in.numberofholes; ++h) {
4595       for (d = 0; d < dim; ++d) {
4596         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4597       }
4598     }
4599   }
4600 #endif
4601   if (!rank) {
4602     char args[32];
4603 
4604     /* Take away 'Q' for verbose output */
4605     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4606     triangulate(args, &in, &out, PETSC_NULL);
4607   }
4608   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4609   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4610   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4611   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4612   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4613 
4614   {
4615     const PetscInt numCorners  = 3;
4616     const PetscInt numCells    = out.numberoftriangles;
4617     const PetscInt numVertices = out.numberofpoints;
4618     const int     *cells       = out.trianglelist;
4619     const double  *meshCoords  = out.pointlist;
4620     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4621 
4622     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4623     /* Set labels */
4624     for (v = 0; v < numVertices; ++v) {
4625       if (out.pointmarkerlist[v]) {
4626         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4627       }
4628     }
4629     if (interpolate) {
4630       PetscInt e;
4631 
4632       for (e = 0; e < out.numberofedges; e++) {
4633         if (out.edgemarkerlist[e]) {
4634           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4635           const PetscInt *edges;
4636           PetscInt        numEdges;
4637 
4638           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4639           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4640           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4641           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4642         }
4643       }
4644     }
4645     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4646   }
4647 #if 0 /* Do not currently support holes */
4648   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4649 #endif
4650   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4651   PetscFunctionReturn(0);
4652 }
4653 #endif
4654 
4655 #ifdef PETSC_HAVE_TETGEN
4656 #include <tetgen.h>
4657 #undef __FUNCT__
4658 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4659 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4660 {
4661   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4662   const PetscInt dim  = 3;
4663   ::tetgenio     in;
4664   ::tetgenio     out;
4665   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4666   PetscMPIInt    rank;
4667   PetscErrorCode ierr;
4668 
4669   PetscFunctionBegin;
4670   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4671   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4672   in.numberofpoints = vEnd - vStart;
4673   if (in.numberofpoints > 0) {
4674     PetscSection coordSection;
4675     Vec          coordinates;
4676     PetscScalar *array;
4677 
4678     in.pointlist       = new double[in.numberofpoints*dim];
4679     in.pointmarkerlist = new int[in.numberofpoints];
4680     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4681     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4682     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4683     for (v = vStart; v < vEnd; ++v) {
4684       const PetscInt idx = v - vStart;
4685       PetscInt       off, d;
4686 
4687       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4688       for (d = 0; d < dim; ++d) {
4689         in.pointlist[idx*dim + d] = array[off+d];
4690       }
4691       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4692     }
4693     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4694   }
4695   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4696   in.numberoffacets = fEnd - fStart;
4697   if (in.numberoffacets > 0) {
4698     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4699     in.facetmarkerlist = new int[in.numberoffacets];
4700     for (f = fStart; f < fEnd; ++f) {
4701       const PetscInt idx    = f - fStart;
4702       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
4703 
4704       in.facetlist[idx].numberofpolygons = 1;
4705       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4706       in.facetlist[idx].numberofholes    = 0;
4707       in.facetlist[idx].holelist         = NULL;
4708 
4709       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4710       for (p = 0; p < numPoints*2; p += 2) {
4711         const PetscInt point = points[p];
4712         if ((point >= vStart) && (point < vEnd)) {
4713           points[numVertices++] = point;
4714         }
4715       }
4716 
4717       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4718       poly->numberofvertices = numVertices;
4719       poly->vertexlist       = new int[poly->numberofvertices];
4720       for (v = 0; v < numVertices; ++v) {
4721         const PetscInt vIdx = points[v] - vStart;
4722         poly->vertexlist[v] = vIdx;
4723       }
4724       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4725       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4726     }
4727   }
4728   if (!rank) {
4729     char args[32];
4730 
4731     /* Take away 'Q' for verbose output */
4732     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4733     ::tetrahedralize(args, &in, &out);
4734   }
4735   {
4736     const PetscInt numCorners  = 4;
4737     const PetscInt numCells    = out.numberoftetrahedra;
4738     const PetscInt numVertices = out.numberofpoints;
4739     const int     *cells       = out.tetrahedronlist;
4740     const double  *meshCoords  = out.pointlist;
4741 
4742     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4743     /* Set labels */
4744     for (v = 0; v < numVertices; ++v) {
4745       if (out.pointmarkerlist[v]) {
4746         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4747       }
4748     }
4749     if (interpolate) {
4750       PetscInt e;
4751 
4752       for (e = 0; e < out.numberofedges; e++) {
4753         if (out.edgemarkerlist[e]) {
4754           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4755           const PetscInt *edges;
4756           PetscInt        numEdges;
4757 
4758           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4759           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4760           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4761           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4762         }
4763       }
4764       for (f = 0; f < out.numberoftrifaces; f++) {
4765         if (out.trifacemarkerlist[f]) {
4766           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4767           const PetscInt *faces;
4768           PetscInt        numFaces;
4769 
4770           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4771           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4772           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4773           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4774         }
4775       }
4776     }
4777     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4778   }
4779   PetscFunctionReturn(0);
4780 }
4781 
4782 #undef __FUNCT__
4783 #define __FUNCT__ "DMPlexRefine_Tetgen"
4784 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4785 {
4786   MPI_Comm       comm = ((PetscObject) dm)->comm;
4787   const PetscInt dim  = 3;
4788   ::tetgenio     in;
4789   ::tetgenio     out;
4790   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4791   PetscMPIInt    rank;
4792   PetscErrorCode ierr;
4793 
4794   PetscFunctionBegin;
4795   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4796   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4797   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4798   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4799   in.numberofpoints = vEnd - vStart;
4800   if (in.numberofpoints > 0) {
4801     PetscSection coordSection;
4802     Vec          coordinates;
4803     PetscScalar *array;
4804 
4805     in.pointlist       = new double[in.numberofpoints*dim];
4806     in.pointmarkerlist = new int[in.numberofpoints];
4807     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4808     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4809     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4810     for (v = vStart; v < vEnd; ++v) {
4811       const PetscInt idx = v - vStart;
4812       PetscInt       off, d;
4813 
4814       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4815       for (d = 0; d < dim; ++d) {
4816         in.pointlist[idx*dim + d] = array[off+d];
4817       }
4818       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4819     }
4820     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4821   }
4822   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4823   in.numberofcorners       = 4;
4824   in.numberoftetrahedra    = cEnd - cStart;
4825   in.tetrahedronvolumelist = (double *) maxVolumes;
4826   if (in.numberoftetrahedra > 0) {
4827     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
4828     for (c = cStart; c < cEnd; ++c) {
4829       const PetscInt idx     = c - cStart;
4830       PetscInt      *closure = PETSC_NULL;
4831       PetscInt       closureSize;
4832 
4833       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4834       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4835       for (v = 0; v < 4; ++v) {
4836         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4837       }
4838       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4839     }
4840   }
4841   // TODO: Put in boundary faces with markers
4842   if (!rank) {
4843     char args[32];
4844 
4845     /* Take away 'Q' for verbose output */
4846     //ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr);
4847     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
4848     ::tetrahedralize(args, &in, &out);
4849   }
4850   in.tetrahedronvolumelist = NULL;
4851 
4852   {
4853     const PetscInt numCorners  = 4;
4854     const PetscInt numCells    = out.numberoftetrahedra;
4855     const PetscInt numVertices = out.numberofpoints;
4856     const int     *cells       = out.tetrahedronlist;
4857     const double  *meshCoords  = out.pointlist;
4858     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4859 
4860     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4861     /* Set labels */
4862     for (v = 0; v < numVertices; ++v) {
4863       if (out.pointmarkerlist[v]) {
4864         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4865       }
4866     }
4867     if (interpolate) {
4868       PetscInt e, f;
4869 
4870       for (e = 0; e < out.numberofedges; e++) {
4871         if (out.edgemarkerlist[e]) {
4872           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4873           const PetscInt *edges;
4874           PetscInt        numEdges;
4875 
4876           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4877           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4878           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4879           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4880         }
4881       }
4882       for (f = 0; f < out.numberoftrifaces; f++) {
4883         if (out.trifacemarkerlist[f]) {
4884           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4885           const PetscInt *faces;
4886           PetscInt        numFaces;
4887 
4888           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4889           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4890           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4891           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4892         }
4893       }
4894     }
4895     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4896   }
4897   PetscFunctionReturn(0);
4898 }
4899 #endif
4900 
4901 #ifdef PETSC_HAVE_CTETGEN
4902 #include "ctetgen.h"
4903 
4904 #undef __FUNCT__
4905 #define __FUNCT__ "DMPlexGenerate_CTetgen"
4906 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4907 {
4908   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4909   const PetscInt dim  = 3;
4910   PLC           *in, *out;
4911   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4912   PetscMPIInt    rank;
4913   PetscErrorCode ierr;
4914 
4915   PetscFunctionBegin;
4916   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
4917   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4918   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4919   ierr = PLCCreate(&in);CHKERRQ(ierr);
4920   ierr = PLCCreate(&out);CHKERRQ(ierr);
4921   in->numberofpoints = vEnd - vStart;
4922   if (in->numberofpoints > 0) {
4923     PetscSection coordSection;
4924     Vec          coordinates;
4925     PetscScalar *array;
4926 
4927     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4928     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4929     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4930     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4931     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4932     for (v = vStart; v < vEnd; ++v) {
4933       const PetscInt idx = v - vStart;
4934       PetscInt       off, d, m;
4935 
4936       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4937       for (d = 0; d < dim; ++d) {
4938         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4939       }
4940       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
4941       in->pointmarkerlist[idx] = (int) m;
4942     }
4943     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4944   }
4945   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4946   in->numberoffacets = fEnd - fStart;
4947   if (in->numberoffacets > 0) {
4948     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
4949     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
4950     for (f = fStart; f < fEnd; ++f) {
4951       const PetscInt idx    = f - fStart;
4952       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
4953       polygon       *poly;
4954 
4955       in->facetlist[idx].numberofpolygons = 1;
4956       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
4957       in->facetlist[idx].numberofholes    = 0;
4958       in->facetlist[idx].holelist         = PETSC_NULL;
4959 
4960       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4961       for (p = 0; p < numPoints*2; p += 2) {
4962         const PetscInt point = points[p];
4963         if ((point >= vStart) && (point < vEnd)) {
4964           points[numVertices++] = point;
4965         }
4966       }
4967 
4968       poly = in->facetlist[idx].polygonlist;
4969       poly->numberofvertices = numVertices;
4970       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
4971       for (v = 0; v < numVertices; ++v) {
4972         const PetscInt vIdx = points[v] - vStart;
4973         poly->vertexlist[v] = vIdx;
4974       }
4975       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
4976       in->facetmarkerlist[idx] = (int) m;
4977       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4978     }
4979   }
4980   if (!rank) {
4981     TetGenOpts t;
4982 
4983     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4984     t.in        = boundary; /* Should go away */
4985     t.plc       = 1;
4986     t.quality   = 1;
4987     t.edgesout  = 1;
4988     t.zeroindex = 1;
4989     t.quiet     = 1;
4990     t.verbose   = verbose;
4991     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
4992     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4993   }
4994   {
4995     const PetscInt numCorners  = 4;
4996     const PetscInt numCells    = out->numberoftetrahedra;
4997     const PetscInt numVertices = out->numberofpoints;
4998     const int     *cells       = out->tetrahedronlist;
4999     const double  *meshCoords  = out->pointlist;
5000 
5001     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5002     /* Set labels */
5003     for (v = 0; v < numVertices; ++v) {
5004       if (out->pointmarkerlist[v]) {
5005         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5006       }
5007     }
5008     if (interpolate) {
5009       PetscInt e;
5010 
5011       for (e = 0; e < out->numberofedges; e++) {
5012         if (out->edgemarkerlist[e]) {
5013           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5014           const PetscInt *edges;
5015           PetscInt        numEdges;
5016 
5017           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5018           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5019           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5020           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5021         }
5022       }
5023       for (f = 0; f < out->numberoftrifaces; f++) {
5024         if (out->trifacemarkerlist[f]) {
5025           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5026           const PetscInt *faces;
5027           PetscInt        numFaces;
5028 
5029           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5030           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5031           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5032           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5033         }
5034       }
5035     }
5036     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5037   }
5038 
5039   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5040   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5041   PetscFunctionReturn(0);
5042 }
5043 
5044 #undef __FUNCT__
5045 #define __FUNCT__ "DMPlexRefine_CTetgen"
5046 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5047 {
5048   MPI_Comm       comm = ((PetscObject) dm)->comm;
5049   const PetscInt dim  = 3;
5050   PLC           *in, *out;
5051   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5052   PetscMPIInt    rank;
5053   PetscErrorCode ierr;
5054 
5055   PetscFunctionBegin;
5056   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5057   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5058   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5059   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5060   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5061   ierr = PLCCreate(&in);CHKERRQ(ierr);
5062   ierr = PLCCreate(&out);CHKERRQ(ierr);
5063   in->numberofpoints = vEnd - vStart;
5064   if (in->numberofpoints > 0) {
5065     PetscSection coordSection;
5066     Vec          coordinates;
5067     PetscScalar *array;
5068 
5069     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5070     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5071     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5072     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5073     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5074     for (v = vStart; v < vEnd; ++v) {
5075       const PetscInt idx = v - vStart;
5076       PetscInt       off, d, m;
5077 
5078       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5079       for (d = 0; d < dim; ++d) {
5080         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5081       }
5082       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5083       in->pointmarkerlist[idx] = (int) m;
5084     }
5085     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5086   }
5087   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5088   in->numberofcorners       = 4;
5089   in->numberoftetrahedra    = cEnd - cStart;
5090   in->tetrahedronvolumelist = maxVolumes;
5091   if (in->numberoftetrahedra > 0) {
5092     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5093     for (c = cStart; c < cEnd; ++c) {
5094       const PetscInt idx     = c - cStart;
5095       PetscInt      *closure = PETSC_NULL;
5096       PetscInt       closureSize;
5097 
5098       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5099       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5100       for (v = 0; v < 4; ++v) {
5101         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5102       }
5103       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5104     }
5105   }
5106   if (!rank) {
5107     TetGenOpts t;
5108 
5109     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5110     t.in        = dm; /* Should go away */
5111     t.refine    = 1;
5112     t.varvolume = 1;
5113     t.quality   = 1;
5114     t.edgesout  = 1;
5115     t.zeroindex = 1;
5116     t.quiet     = 1;
5117     t.verbose   = verbose; /* Change this */
5118     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5119     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5120   }
5121   {
5122     const PetscInt numCorners  = 4;
5123     const PetscInt numCells    = out->numberoftetrahedra;
5124     const PetscInt numVertices = out->numberofpoints;
5125     const int     *cells       = out->tetrahedronlist;
5126     const double  *meshCoords  = out->pointlist;
5127     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5128 
5129     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5130     /* Set labels */
5131     for (v = 0; v < numVertices; ++v) {
5132       if (out->pointmarkerlist[v]) {
5133         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5134       }
5135     }
5136     if (interpolate) {
5137       PetscInt e, f;
5138 
5139       for (e = 0; e < out->numberofedges; e++) {
5140         if (out->edgemarkerlist[e]) {
5141           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5142           const PetscInt *edges;
5143           PetscInt        numEdges;
5144 
5145           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5146           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5147           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5148           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5149         }
5150       }
5151       for (f = 0; f < out->numberoftrifaces; f++) {
5152         if (out->trifacemarkerlist[f]) {
5153           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5154           const PetscInt *faces;
5155           PetscInt        numFaces;
5156 
5157           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5158           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5159           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5160           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5161         }
5162       }
5163     }
5164     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5165   }
5166   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5167   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5168   PetscFunctionReturn(0);
5169 }
5170 #endif
5171 
5172 #undef __FUNCT__
5173 #define __FUNCT__ "DMPlexGenerate"
5174 /*@C
5175   DMPlexGenerate - Generates a mesh.
5176 
5177   Not Collective
5178 
5179   Input Parameters:
5180 + boundary - The DMPlex boundary object
5181 . name - The mesh generation package name
5182 - interpolate - Flag to create intermediate mesh elements
5183 
5184   Output Parameter:
5185 . mesh - The DMPlex object
5186 
5187   Level: intermediate
5188 
5189 .keywords: mesh, elements
5190 .seealso: DMPlexCreate(), DMRefine()
5191 @*/
5192 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5193 {
5194   PetscInt       dim;
5195   char           genname[1024];
5196   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5197   PetscErrorCode ierr;
5198 
5199   PetscFunctionBegin;
5200   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5201   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5202   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5203   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5204   if (flg) {name = genname;}
5205   if (name) {
5206     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5207     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5208     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5209   }
5210   switch(dim) {
5211   case 1:
5212     if (!name || isTriangle) {
5213 #ifdef PETSC_HAVE_TRIANGLE
5214       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5215 #else
5216       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5217 #endif
5218     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5219     break;
5220   case 2:
5221     if (!name || isCTetgen) {
5222 #ifdef PETSC_HAVE_CTETGEN
5223       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5224 #else
5225       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5226 #endif
5227     } else if (isTetgen) {
5228 #ifdef PETSC_HAVE_TETGEN
5229       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5230 #else
5231       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5232 #endif
5233     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5234     break;
5235   default:
5236     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5237   }
5238   PetscFunctionReturn(0);
5239 }
5240 
5241 typedef PetscInt CellRefiner;
5242 
5243 #undef __FUNCT__
5244 #define __FUNCT__ "GetDepthStart_Private"
5245 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5246 {
5247   PetscFunctionBegin;
5248   if (cStart) *cStart = 0;
5249   if (vStart) *vStart = depthSize[depth];
5250   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5251   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5252   PetscFunctionReturn(0);
5253 }
5254 
5255 #undef __FUNCT__
5256 #define __FUNCT__ "GetDepthEnd_Private"
5257 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5258 {
5259   PetscFunctionBegin;
5260   if (cEnd) *cEnd = depthSize[depth];
5261   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5262   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5263   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5264   PetscFunctionReturn(0);
5265 }
5266 
5267 #undef __FUNCT__
5268 #define __FUNCT__ "CellRefinerGetSizes"
5269 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5270 {
5271   PetscInt       cStart, cEnd, vStart, vEnd, fStart, fEnd, eStart, eEnd;
5272   PetscErrorCode ierr;
5273 
5274   PetscFunctionBegin;
5275   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5276   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5277   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5278   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5279   switch(refiner) {
5280   case 1:
5281     /* Simplicial 2D */
5282     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5283     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5284     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5285     break;
5286   case 2:
5287     /* Hex 2D */
5288     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5289     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5290     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5291     break;
5292   default:
5293     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5294   }
5295   PetscFunctionReturn(0);
5296 }
5297 
5298 #undef __FUNCT__
5299 #define __FUNCT__ "CellRefinerSetConeSizes"
5300 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5301 {
5302   PetscInt       depth, cStart, cStartNew, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fStartNew, fEnd, f, eStart, eStartNew, eEnd, r;
5303   PetscErrorCode ierr;
5304 
5305   PetscFunctionBegin;
5306   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5307   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5308   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5309   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5310   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5311   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5312   switch(refiner) {
5313   case 1:
5314     /* Simplicial 2D */
5315     /* All cells have 3 faces */
5316     for(c = cStart; c < cEnd; ++c) {
5317       for(r = 0; r < 4; ++r) {
5318         const PetscInt newp = (c - cStart)*4 + r;
5319 
5320         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5321       }
5322     }
5323     /* Split faces have 2 vertices and the same cells as the parent */
5324     for(f = fStart; f < fEnd; ++f) {
5325       for(r = 0; r < 2; ++r) {
5326         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5327         PetscInt       size;
5328 
5329         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5330         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5331         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5332       }
5333     }
5334     /* Interior faces have 2 vertices and 2 cells */
5335     for(c = cStart; c < cEnd; ++c) {
5336       for(r = 0; r < 3; ++r) {
5337         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5338 
5339         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5340         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5341       }
5342     }
5343     /* Old vertices have identical supports */
5344     for(v = vStart; v < vEnd; ++v) {
5345       const PetscInt newp = vStartNew + (v - vStart);
5346       PetscInt       size;
5347 
5348       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5349       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5350     }
5351     /* Face vertices have 2 + cells*2 supports */
5352     for(f = fStart; f < fEnd; ++f) {
5353       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5354       PetscInt       size;
5355 
5356       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5357       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5358     }
5359     break;
5360   case 2:
5361     /* Hex 2D */
5362     /* All cells have 4 faces */
5363     for(c = cStart; c < cEnd; ++c) {
5364       for(r = 0; r < 4; ++r) {
5365         const PetscInt newp = (c - cStart)*4 + r;
5366 
5367         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5368       }
5369     }
5370     /* Split faces have 2 vertices and the same cells as the parent */
5371     for(f = fStart; f < fEnd; ++f) {
5372       for(r = 0; r < 2; ++r) {
5373         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5374         PetscInt       size;
5375 
5376         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5377         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5378         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5379       }
5380     }
5381     /* Interior faces have 2 vertices and 2 cells */
5382     for(c = cStart; c < cEnd; ++c) {
5383       for(r = 0; r < 4; ++r) {
5384         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5385 
5386         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5387         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5388       }
5389     }
5390     /* Old vertices have identical supports */
5391     for(v = vStart; v < vEnd; ++v) {
5392       const PetscInt newp = vStartNew + (v - vStart);
5393       PetscInt       size;
5394 
5395       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5396       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5397     }
5398     /* Face vertices have 2 + cells supports */
5399     for(f = fStart; f < fEnd; ++f) {
5400       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5401       PetscInt       size;
5402 
5403       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5404       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5405     }
5406     /* Cell vertices have 4 supports */
5407     for(c = cStart; c < cEnd; ++c) {
5408       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5409 
5410       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5411     }
5412     break;
5413   default:
5414     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5415   }
5416   PetscFunctionReturn(0);
5417 }
5418 
5419 #undef __FUNCT__
5420 #define __FUNCT__ "CellRefinerSetCones"
5421 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5422 {
5423   PetscInt       depth, cStart, cEnd, cStartNew, cEndNew, c, vStart, vEnd, vStartNew, vEndNew, v, fStart, fEnd, fStartNew, fEndNew, f, eStart, eEnd, eStartNew, eEndNew, r, p;
5424   PetscInt       maxSupportSize, *supportRef;
5425   PetscErrorCode ierr;
5426 
5427   PetscFunctionBegin;
5428   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5429   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5430   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5431   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5432   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5433   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5434   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5435   switch(refiner) {
5436   case 1:
5437     /* Simplicial 2D */
5438     /*
5439      2
5440      |\
5441      | \
5442      |  \
5443      |   \
5444      | C  \
5445      |     \
5446      |      \
5447      2---1---1
5448      |\  D  / \
5449      | 2   0   \
5450      |A \ /  B  \
5451      0---0-------1
5452      */
5453     /* All cells have 3 faces */
5454     for(c = cStart; c < cEnd; ++c) {
5455       const PetscInt  newp = (c - cStart)*4;
5456       const PetscInt *cone, *ornt;
5457       PetscInt        coneNew[3], orntNew[3];
5458 
5459       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5460       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5461       /* A triangle */
5462       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5463       orntNew[0] = ornt[0];
5464       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5465       orntNew[1] = -2;
5466       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5467       orntNew[2] = ornt[2];
5468       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5469       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5470 #if 1
5471       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);
5472       for(p = 0; p < 3; ++p) {
5473         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);
5474       }
5475 #endif
5476       /* B triangle */
5477       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5478       orntNew[0] = ornt[0];
5479       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5480       orntNew[1] = ornt[1];
5481       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5482       orntNew[2] = -2;
5483       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5484       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5485 #if 1
5486       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);
5487       for(p = 0; p < 3; ++p) {
5488         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);
5489       }
5490 #endif
5491       /* C triangle */
5492       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5493       orntNew[0] = -2;
5494       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5495       orntNew[1] = ornt[1];
5496       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5497       orntNew[2] = ornt[2];
5498       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5499       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5500 #if 1
5501       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);
5502       for(p = 0; p < 3; ++p) {
5503         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);
5504       }
5505 #endif
5506       /* D triangle */
5507       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5508       orntNew[0] = 0;
5509       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5510       orntNew[1] = 0;
5511       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5512       orntNew[2] = 0;
5513       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5514       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5515 #if 1
5516       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);
5517       for(p = 0; p < 3; ++p) {
5518         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);
5519       }
5520 #endif
5521     }
5522     /* Split faces have 2 vertices and the same cells as the parent */
5523     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5524     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5525     for(f = fStart; f < fEnd; ++f) {
5526       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5527 
5528       for(r = 0; r < 2; ++r) {
5529         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5530         const PetscInt *cone, *support;
5531         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5532 
5533         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5534         coneNew[0] = vStartNew + (cone[0] - vStart);
5535         coneNew[1] = vStartNew + (cone[1] - vStart);
5536         coneNew[(r+1)%2] = newv;
5537         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5538 #if 1
5539         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5540         for(p = 0; p < 2; ++p) {
5541           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);
5542         }
5543 #endif
5544         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5545         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5546         for(s = 0; s < supportSize; ++s) {
5547           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5548           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5549           for(c = 0; c < coneSize; ++c) {
5550             if (cone[c] == f) {
5551               break;
5552             }
5553           }
5554           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5555         }
5556         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5557 #if 1
5558         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5559         for(p = 0; p < supportSize; ++p) {
5560           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);
5561         }
5562 #endif
5563       }
5564     }
5565     /* Interior faces have 2 vertices and 2 cells */
5566     for(c = cStart; c < cEnd; ++c) {
5567       const PetscInt *cone;
5568 
5569       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5570       for(r = 0; r < 3; ++r) {
5571         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5572         PetscInt       coneNew[2];
5573         PetscInt       supportNew[2];
5574 
5575         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5576         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5577         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5578 #if 1
5579         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5580         for(p = 0; p < 2; ++p) {
5581           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);
5582         }
5583 #endif
5584         supportNew[0] = (c - cStart)*4 + r;
5585         supportNew[1] = (c - cStart)*4 + 3;
5586         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5587 #if 1
5588         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5589         for(p = 0; p < 2; ++p) {
5590           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);
5591         }
5592 #endif
5593       }
5594     }
5595     /* Old vertices have identical supports */
5596     for(v = vStart; v < vEnd; ++v) {
5597       const PetscInt  newp = vStartNew + (v - vStart);
5598       const PetscInt *support, *cone;
5599       PetscInt        size, s;
5600 
5601       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5602       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5603       for(s = 0; s < size; ++s) {
5604         PetscInt r = 0;
5605 
5606         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5607         if (cone[1] == v) r = 1;
5608         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5609       }
5610       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5611 #if 1
5612       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5613       for(p = 0; p < size; ++p) {
5614         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);
5615       }
5616 #endif
5617     }
5618     /* Face vertices have 2 + cells*2 supports */
5619     for(f = fStart; f < fEnd; ++f) {
5620       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5621       const PetscInt *cone, *support;
5622       PetscInt        size, s;
5623 
5624       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5625       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5626       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5627       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5628       for(s = 0; s < size; ++s) {
5629         PetscInt r = 0;
5630 
5631         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5632         if      (cone[1] == f) r = 1;
5633         else if (cone[2] == f) r = 2;
5634         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5635         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5636       }
5637       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5638 #if 1
5639       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5640       for(p = 0; p < 2+size*2; ++p) {
5641         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);
5642       }
5643 #endif
5644     }
5645     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5646     break;
5647   case 2:
5648     /* Hex 2D */
5649     /*
5650      3---------2---------2
5651      |         |         |
5652      |    D    2    C    |
5653      |         |         |
5654      3----3----0----1----1
5655      |         |         |
5656      |    A    0    B    |
5657      |         |         |
5658      0---------0---------1
5659      */
5660     /* All cells have 4 faces */
5661     for(c = cStart; c < cEnd; ++c) {
5662       const PetscInt  newp = (c - cStart)*4;
5663       const PetscInt *cone, *ornt;
5664       PetscInt        coneNew[4], orntNew[4];
5665 
5666       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5667       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5668       /* A quad */
5669       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5670       orntNew[0] = ornt[0];
5671       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5672       orntNew[1] = 0;
5673       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5674       orntNew[2] = -2;
5675       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5676       orntNew[3] = ornt[3];
5677       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5678       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5679 #if 1
5680       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);
5681       for(p = 0; p < 4; ++p) {
5682         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);
5683       }
5684 #endif
5685       /* B quad */
5686       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5687       orntNew[0] = ornt[0];
5688       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5689       orntNew[1] = ornt[1];
5690       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5691       orntNew[2] = 0;
5692       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5693       orntNew[3] = -2;
5694       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5695       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5696 #if 1
5697       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);
5698       for(p = 0; p < 4; ++p) {
5699         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);
5700       }
5701 #endif
5702       /* C quad */
5703       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5704       orntNew[0] = -2;
5705       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5706       orntNew[1] = ornt[1];
5707       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5708       orntNew[2] = ornt[2];
5709       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5710       orntNew[3] = 0;
5711       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5712       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5713 #if 1
5714       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);
5715       for(p = 0; p < 4; ++p) {
5716         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);
5717       }
5718 #endif
5719       /* D quad */
5720       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5721       orntNew[0] = 0;
5722       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5723       orntNew[1] = -2;
5724       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5725       orntNew[2] = ornt[2];
5726       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
5727       orntNew[3] = ornt[3];
5728       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5729       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5730 #if 1
5731       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);
5732       for(p = 0; p < 4; ++p) {
5733         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);
5734       }
5735 #endif
5736     }
5737     /* Split faces have 2 vertices and the same cells as the parent */
5738     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5739     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5740     for(f = fStart; f < fEnd; ++f) {
5741       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5742 
5743       for(r = 0; r < 2; ++r) {
5744         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5745         const PetscInt *cone, *support;
5746         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5747 
5748         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5749         coneNew[0] = vStartNew + (cone[0] - vStart);
5750         coneNew[1] = vStartNew + (cone[1] - vStart);
5751         coneNew[(r+1)%2] = newv;
5752         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5753 #if 1
5754         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5755         for(p = 0; p < 2; ++p) {
5756           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);
5757         }
5758 #endif
5759         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5760         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5761         for(s = 0; s < supportSize; ++s) {
5762           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5763           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5764           for(c = 0; c < coneSize; ++c) {
5765             if (cone[c] == f) {
5766               break;
5767             }
5768           }
5769           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
5770         }
5771         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5772 #if 1
5773         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5774         for(p = 0; p < supportSize; ++p) {
5775           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);
5776         }
5777 #endif
5778       }
5779     }
5780     /* Interior faces have 2 vertices and 2 cells */
5781     for(c = cStart; c < cEnd; ++c) {
5782       const PetscInt *cone;
5783       PetscInt        coneNew[2], supportNew[2];
5784 
5785       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5786       for(r = 0; r < 4; ++r) {
5787         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5788 
5789         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
5790         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
5791         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5792 #if 1
5793         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5794         for(p = 0; p < 2; ++p) {
5795           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);
5796         }
5797 #endif
5798         supportNew[0] = (c - cStart)*4 + r;
5799         supportNew[1] = (c - cStart)*4 + (r+1)%4;
5800         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5801 #if 1
5802         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5803         for(p = 0; p < 2; ++p) {
5804           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);
5805         }
5806 #endif
5807       }
5808     }
5809     /* Old vertices have identical supports */
5810     for(v = vStart; v < vEnd; ++v) {
5811       const PetscInt  newp = vStartNew + (v - vStart);
5812       const PetscInt *support, *cone;
5813       PetscInt        size, s;
5814 
5815       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5816       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5817       for(s = 0; s < size; ++s) {
5818         PetscInt r = 0;
5819 
5820         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5821         if (cone[1] == v) r = 1;
5822         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5823       }
5824       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5825 #if 1
5826       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5827       for(p = 0; p < size; ++p) {
5828         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);
5829       }
5830 #endif
5831     }
5832     /* Face vertices have 2 + cells supports */
5833     for(f = fStart; f < fEnd; ++f) {
5834       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5835       const PetscInt *cone, *support;
5836       PetscInt        size, s;
5837 
5838       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5839       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5840       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5841       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5842       for(s = 0; s < size; ++s) {
5843         PetscInt r = 0;
5844 
5845         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5846         if      (cone[1] == f) r = 1;
5847         else if (cone[2] == f) r = 2;
5848         else if (cone[3] == f) r = 3;
5849         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
5850       }
5851       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5852 #if 1
5853       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5854       for(p = 0; p < 2+size; ++p) {
5855         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);
5856       }
5857 #endif
5858     }
5859     /* Cell vertices have 4 supports */
5860     for(c = cStart; c < cEnd; ++c) {
5861       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5862       PetscInt       supportNew[4];
5863 
5864       for(r = 0; r < 4; ++r) {
5865         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5866       }
5867       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5868     }
5869     break;
5870   default:
5871     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5872   }
5873   PetscFunctionReturn(0);
5874 }
5875 
5876 #undef __FUNCT__
5877 #define __FUNCT__ "CellRefinerSetCoordinates"
5878 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5879 {
5880   PetscSection   coordSection, coordSectionNew;
5881   Vec            coordinates, coordinatesNew;
5882   PetscScalar   *coords, *coordsNew;
5883   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, f;
5884   PetscErrorCode ierr;
5885 
5886   PetscFunctionBegin;
5887   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5888   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5889   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5890   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5891   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5892   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
5893   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5894   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
5895   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5896   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5897   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
5898   switch(refiner) {
5899   case 1:
5900   case 2:
5901     /* Simplicial and Hex 2D */
5902     /* All vertices have the dim coordinates */
5903     for(v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5904       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5905       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5906     }
5907     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5908     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5909     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5910     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5911     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
5912     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5913     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5914     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5915     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5916     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5917     /* Old vertices have the same coordinates */
5918     for(v = vStart; v < vEnd; ++v) {
5919       const PetscInt newv = vStartNew + (v - vStart);
5920       PetscInt       off, offnew, d;
5921 
5922       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5923       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5924       for(d = 0; d < dim; ++d) {
5925         coordsNew[offnew+d] = coords[off+d];
5926       }
5927     }
5928     /* Face vertices have the average of endpoint coordinates */
5929     for(f = fStart; f < fEnd; ++f) {
5930       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5931       const PetscInt *cone;
5932       PetscInt        coneSize, offA, offB, offnew, d;
5933 
5934       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5935       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5936       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5937       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5938       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5939       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5940       for(d = 0; d < dim; ++d) {
5941         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5942       }
5943     }
5944     /* Just Hex 2D */
5945     if (refiner == 2) {
5946       /* Cell vertices have the average of corner coordinates */
5947       for(c = cStart; c < cEnd; ++c) {
5948         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5949         PetscInt      *cone = PETSC_NULL;
5950         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5951 
5952         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5953         for(p = 0; p < closureSize*2; p += 2) {
5954           const PetscInt point = cone[p];
5955           if ((point >= vStart) && (point < vEnd)) {
5956             cone[coneSize++] = point;
5957           }
5958         }
5959         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5960         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5961         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5962         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5963         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5964         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5965         for(d = 0; d < dim; ++d) {
5966           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5967         }
5968         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5969       }
5970     }
5971     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5972     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5973     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5974     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5975     break;
5976   default:
5977     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5978   }
5979   PetscFunctionReturn(0);
5980 }
5981 
5982 #undef __FUNCT__
5983 #define __FUNCT__ "DMPlexCreateProcessSF"
5984 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5985 {
5986   PetscInt           numRoots, numLeaves, l;
5987   const PetscInt    *localPoints;
5988   const PetscSFNode *remotePoints;
5989   PetscInt          *localPointsNew;
5990   PetscSFNode       *remotePointsNew;
5991   PetscInt          *ranks, *ranksNew;
5992   PetscErrorCode     ierr;
5993 
5994   PetscFunctionBegin;
5995   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5996   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5997   for(l = 0; l < numLeaves; ++l) {
5998     ranks[l] = remotePoints[l].rank;
5999   }
6000   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6001   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6002   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6003   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6004   for(l = 0; l < numLeaves; ++l) {
6005     ranksNew[l]              = ranks[l];
6006     localPointsNew[l]        = l;
6007     remotePointsNew[l].index = 0;
6008     remotePointsNew[l].rank  = ranksNew[l];
6009   }
6010   ierr = PetscFree(ranks);CHKERRQ(ierr);
6011   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6012   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6013   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6014   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6015   PetscFunctionReturn(0);
6016 }
6017 
6018 #undef __FUNCT__
6019 #define __FUNCT__ "CellRefinerCreateSF"
6020 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6021 {
6022   PetscSF            sf, sfNew, sfProcess;
6023   IS                 processRanks;
6024   MPI_Datatype       depthType;
6025   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6026   const PetscInt    *localPoints, *neighbors;
6027   const PetscSFNode *remotePoints;
6028   PetscInt          *localPointsNew;
6029   PetscSFNode       *remotePointsNew;
6030   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6031   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, vStart, vStartNew, vEnd, fStart, fStartNew, fEnd, eStart, eStartNew, eEnd, r, n;
6032   PetscErrorCode     ierr;
6033 
6034   PetscFunctionBegin;
6035   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6036   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6037   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6038   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6039   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6040   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6041   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6042   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6043   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6044   /* Caculate size of new SF */
6045   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6046   if (numRoots < 0) PetscFunctionReturn(0);
6047   for(l = 0; l < numLeaves; ++l) {
6048     const PetscInt p = localPoints[l];
6049 
6050     switch(refiner) {
6051     case 1:
6052       /* Simplicial 2D */
6053       if ((p >= vStart) && (p < vEnd)) {
6054         /* Old vertices stay the same */
6055         ++numLeavesNew;
6056       } else if ((p >= fStart) && (p < fEnd)) {
6057         /* Old faces add new faces and vertex */
6058         numLeavesNew += 1 + 2;
6059       } else if ((p >= cStart) && (p < cEnd)) {
6060         /* Old cells add new cells and interior faces */
6061         numLeavesNew += 4 + 3;
6062       }
6063       break;
6064     case 2:
6065       /* Hex 2D */
6066       if ((p >= vStart) && (p < vEnd)) {
6067         /* Old vertices stay the same */
6068         ++numLeavesNew;
6069       } else if ((p >= fStart) && (p < fEnd)) {
6070         /* Old faces add new faces and vertex */
6071         numLeavesNew += 1 + 2;
6072       } else if ((p >= cStart) && (p < cEnd)) {
6073         /* Old cells add new cells and interior faces */
6074         numLeavesNew += 4 + 4;
6075       }
6076       break;
6077     default:
6078       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6079     }
6080   }
6081   /* Communicate depthSizes for each remote rank */
6082   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6083   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6084   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6085   ierr = PetscMalloc6(depth+1,PetscInt,&depthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthSizeOld,numNeighbors,PetscInt,&rvStart,numNeighbors,PetscInt,&reStart,numNeighbors,PetscInt,&rfStart,numNeighbors,PetscInt,&rcStart);CHKERRQ(ierr);
6086   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6087   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6088   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6089   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6090   for(n = 0; n < numNeighbors; ++n) {
6091     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6092   }
6093   depthSizeOld[depth]   = cEnd - cStart;
6094   depthSizeOld[0]       = vEnd - vStart;
6095   depthSizeOld[depth-1] = fEnd - fStart;
6096   depthSizeOld[1]       = eEnd - eStart;
6097   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6098   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6099   for(n = 0; n < numNeighbors; ++n) {
6100     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6101   }
6102   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6103   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6104   /* Calculate new point SF */
6105   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6106   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6107   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6108   for(l = 0, m = 0; l < numLeaves; ++l) {
6109     PetscInt    p     = localPoints[l];
6110     PetscInt    rp    = remotePoints[l].index, n;
6111     PetscMPIInt rrank = remotePoints[l].rank;
6112 
6113     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6114     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6115     switch(refiner) {
6116     case 1:
6117       /* Simplicial 2D */
6118       if ((p >= vStart) && (p < vEnd)) {
6119         /* Old vertices stay the same */
6120         localPointsNew[m]        = vStartNew     + (p  - vStart);
6121         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6122         remotePointsNew[m].rank  = rrank;
6123         ++m;
6124       } else if ((p >= fStart) && (p < fEnd)) {
6125         /* Old faces add new faces and vertex */
6126         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6127         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6128         remotePointsNew[m].rank  = rrank;
6129         ++m;
6130         for(r = 0; r < 2; ++r, ++m) {
6131           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6132           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6133           remotePointsNew[m].rank  = rrank;
6134         }
6135       } else if ((p >= cStart) && (p < cEnd)) {
6136         /* Old cells add new cells and interior faces */
6137         for(r = 0; r < 4; ++r, ++m) {
6138           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6139           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6140           remotePointsNew[m].rank  = rrank;
6141         }
6142         for(r = 0; r < 3; ++r, ++m) {
6143           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6144           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6145           remotePointsNew[m].rank  = rrank;
6146         }
6147       }
6148       break;
6149     case 2:
6150       /* Hex 2D */
6151       if ((p >= vStart) && (p < vEnd)) {
6152         /* Old vertices stay the same */
6153         localPointsNew[m]        = vStartNew     + (p  - vStart);
6154         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6155         remotePointsNew[m].rank  = rrank;
6156         ++m;
6157       } else if ((p >= fStart) && (p < fEnd)) {
6158         /* Old faces add new faces and vertex */
6159         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6160         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6161         remotePointsNew[m].rank  = rrank;
6162         ++m;
6163         for(r = 0; r < 2; ++r, ++m) {
6164           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6165           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6166           remotePointsNew[m].rank  = rrank;
6167         }
6168       } else if ((p >= cStart) && (p < cEnd)) {
6169         /* Old cells add new cells and interior faces */
6170         for(r = 0; r < 4; ++r, ++m) {
6171           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6172           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6173           remotePointsNew[m].rank  = rrank;
6174         }
6175         for(r = 0; r < 4; ++r, ++m) {
6176           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6177           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6178           remotePointsNew[m].rank  = rrank;
6179         }
6180       }
6181       break;
6182     default:
6183       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6184     }
6185   }
6186   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6187   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6188   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6189   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6190   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6191   PetscFunctionReturn(0);
6192 }
6193 
6194 #undef __FUNCT__
6195 #define __FUNCT__ "CellRefinerCreateLabels"
6196 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6197 {
6198   PetscInt       numLabels, l;
6199   PetscInt       newp, cStart, cEnd, vStart, vStartNew, vEnd, fStart, fStartNew, fEnd, eStart, eEnd, r;
6200   PetscErrorCode ierr;
6201 
6202   PetscFunctionBegin;
6203   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6204   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6205   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6206   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6207   vStartNew = depthSize[2];
6208   fStartNew = depthSize[2] + depthSize[0];
6209   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6210   for(l = 0; l < numLabels; ++l) {
6211     DMLabel         label, labelNew;
6212     const char     *lname;
6213     PetscBool       isDepth;
6214     IS              valueIS;
6215     const PetscInt *values;
6216     PetscInt        numValues, val;
6217 
6218     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6219     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6220     if (isDepth) continue;
6221     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6222     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6223     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6224     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6225     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6226     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6227     for(val = 0; val < numValues; ++val) {
6228       IS              pointIS;
6229       const PetscInt *points;
6230       PetscInt        numPoints, n;
6231 
6232       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6233       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6234       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6235       for(n = 0; n < numPoints; ++n) {
6236         const PetscInt p = points[n];
6237         switch(refiner) {
6238         case 1:
6239           /* Simplicial 2D */
6240           if ((p >= vStart) && (p < vEnd)) {
6241             /* Old vertices stay the same */
6242             newp = vStartNew + (p - vStart);
6243             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6244           } else if ((p >= fStart) && (p < fEnd)) {
6245             /* Old faces add new faces and vertex */
6246             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6247             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6248             for(r = 0; r < 2; ++r) {
6249               newp = fStartNew + (p - fStart)*2 + r;
6250               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6251             }
6252           } else if ((p >= cStart) && (p < cEnd)) {
6253             /* Old cells add new cells and interior faces */
6254             for(r = 0; r < 4; ++r) {
6255               newp = (p - cStart)*4 + r;
6256               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6257             }
6258             for(r = 0; r < 3; ++r) {
6259               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6260               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6261             }
6262           }
6263           break;
6264         case 2:
6265           /* Hex 2D */
6266           if ((p >= vStart) && (p < vEnd)) {
6267             /* Old vertices stay the same */
6268             newp = vStartNew + (p - vStart);
6269             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6270           } else if ((p >= fStart) && (p < fEnd)) {
6271             /* Old faces add new faces and vertex */
6272             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6273             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6274             for(r = 0; r < 2; ++r) {
6275               newp = fStartNew + (p - fStart)*2 + r;
6276               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6277             }
6278           } else if ((p >= cStart) && (p < cEnd)) {
6279             /* Old cells add new cells and interior faces and vertex */
6280             for(r = 0; r < 4; ++r) {
6281               newp = (p - cStart)*4 + r;
6282               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6283             }
6284             for(r = 0; r < 4; ++r) {
6285               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6286               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6287             }
6288             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6289             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6290           }
6291           break;
6292         default:
6293           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6294         }
6295       }
6296       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6297       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6298     }
6299     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6300     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6301     if (0) {
6302       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6303       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6304       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6305     }
6306   }
6307   PetscFunctionReturn(0);
6308 }
6309 
6310 #undef __FUNCT__
6311 #define __FUNCT__ "DMPlexRefine_Uniform"
6312 /* This will only work for interpolated meshes */
6313 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6314 {
6315   DM              rdm;
6316   PetscInt       *depthSize;
6317   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
6318   PetscErrorCode  ierr;
6319 
6320   PetscFunctionBegin;
6321   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
6322   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6323   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6324   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6325   /* Calculate number of new points of each depth */
6326   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6327   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
6328   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6329   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6330   /* Step 1: Set chart */
6331   for(d = 0; d <= depth; ++d) {
6332     pEnd += depthSize[d];
6333   }
6334   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6335   /* Step 2: Set cone/support sizes */
6336   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6337   /* Step 3: Setup refined DM */
6338   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6339   /* Step 4: Set cones and supports */
6340   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6341   /* Step 5: Stratify */
6342   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6343   /* Step 6: Set coordinates for vertices */
6344   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6345   /* Step 7: Create pointSF */
6346   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6347   /* Step 8: Create labels */
6348   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6349   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6350 
6351   *dmRefined = rdm;
6352 #if 0
6353   DM_Plex *mesh = (DM_Plex *) dm->data;
6354   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
6355   //ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize()));
6356 
6357   PetscFunctionBegin;
6358   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6359   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
6360   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6361   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6362   ierr = DMPlexGetVTKBounds(dm, &cMax, &vMax);CHKERRQ(ierr);
6363 
6364   /* Count number of new cells which are normal and extra */
6365   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
6366   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
6367   for(c = cStart; c < cEnd2; ++c) {
6368     PetscInt n;
6369     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); // refiner.numNewCells
6370     newNumCellsNormal += n;
6371   }
6372   for(c = cEnd2; c < cEnd; ++c) {
6373     PetscInt n;
6374     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); // refiner.numNewCells
6375     newNumCellsExtra += n;
6376   }
6377   newNumCells = newNumCellsNormal + newNumCellsExtra;
6378   /* Count number of new vertices which are normal and extra */
6379   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
6380   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
6381   for(c = cStart; c < cEnd; ++c) {
6382     PetscInt *closure = PETSC_NULL;
6383     PetscInt  closureSize, numCorners = 0, p;
6384 
6385     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6386     for(p = 0; p < closureSize*2; p += 2) {
6387       const PetscInt point = closure[p];
6388       if ((point >= vStart) && (point < vEnd)) {
6389         closure[numCorners++] = point;
6390       }
6391     }
6392     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); // refiner.splitCell
6393     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6394   }
6395   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
6396   for(c = cEnd2; c < cEnd; ++c) {
6397     PetscInt *closure = PETSC_NULL;
6398     PetscInt  closureSize, numCorners = 0, p;
6399 
6400     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6401     for(p = 0; p < closureSize*2; p += 2) {
6402       const PetscInt point = closure[p];
6403       if ((point >= vStart) && (point < vEnd)) {
6404         closure[numCorners++] = point;
6405       }
6406     }
6407     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); // refiner.splitCellUncensored
6408     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6409   } // for
6410   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
6411   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
6412 
6413 #if 1
6414   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
6415   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
6416   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
6417   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
6418   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
6419   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
6420   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
6421   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
6422   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
6423   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
6424   ierr = PetscSynchronizedFlush(comm);
6425 #endif
6426 
6427   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
6428   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
6429   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
6430   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
6431   ierr = DMPlexGetVTKBounds(*dmRefined, newNumCellsNormal, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
6432   /* Set cone and support sizes for new normal cells */
6433   PetscInt newCell = 0;
6434   for(c = cStart; c < cEnd2; ++c) {
6435     PetscInt coneSize, n, i;
6436 
6437     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6438     ierr = CellRefinerGetNumSubcells(refiner, c, &n); // refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6439     for(i = 0; i < n; ++i, ++newCell) {
6440       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
6441     }
6442 
6443     PetscInt *closure = PETSC_NULL;
6444     PetscInt  closureSize, numCorners = 0, p;
6445 
6446     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6447     for(p = 0; p < closureSize*2; p += 2) {
6448       const PetscInt point = closure[p];
6449       if ((point >= vStart) && (point < vEnd)) {
6450         closure[numCorners++] = point;
6451       }
6452     }
6453     // ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); // refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6454     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6455   }
6456 
6457   // Reset current new cell value and loop over censored cells.
6458   curNewCell = _orderNewMesh->cellsCensored().min();
6459   oldCellsEnd = _orderOldMesh->cellsCensored().end();
6460   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
6461     // Set new cone and support sizes
6462     cV.clear();
6463     sieve->cone(*c_iter, cV);
6464     const point_type* cone = cV.getPoints();
6465     const int coneSize = cV.getSize();
6466 
6467     const point_type* newCells;
6468     int numNewCells = 0;
6469     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6470 
6471     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
6472       newSieve->setConeSize(curNewCell, coneSize);
6473       for(int iVertex=0; iVertex < coneSize; ++iVertex) {
6474 	newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
6475       } // for
6476     } // for
6477   } // for
6478   newSieve->allocate();
6479 
6480   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
6481 
6482   // Create refined cells in new sieve.
6483   curNewCell = _orderNewMesh->cellsNormal().min();
6484   oldCellsEnd = _orderOldMesh->cellsNormal().end();
6485   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
6486     cV.clear();
6487     sieve->cone(*c_iter, cV);
6488     const point_type *cone = cV.getPoints();
6489     const int coneSize = cV.getSize();
6490 
6491     const point_type* newCells;
6492     int numNewCells = 0;
6493     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6494 
6495     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
6496       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
6497     } // for
6498   } // for
6499   curNewCell = _orderNewMesh->cellsCensored().min();
6500   oldCellsEnd = _orderOldMesh->cellsCensored().end();
6501   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
6502     cV.clear();
6503     sieve->cone(*c_iter, cV);
6504     const point_type *cone = cV.getPoints();
6505     const int coneSize = cV.getSize();
6506 
6507     const point_type* newCells;
6508     int numNewCells = 0;
6509     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6510 
6511     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
6512       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
6513     } // for
6514   } // for
6515   newSieve->symmetrize();
6516 
6517   // Set coordinates in refined mesh.
6518   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
6519   assert(!coordinates.isNull());
6520   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
6521   assert(!newCoordinates.isNull());
6522 
6523   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
6524   assert(vertices->size() > 0);
6525   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
6526   assert(spaceDim > 0);
6527   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
6528 
6529   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
6530   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
6531     newCoordinates->setFiberDimension(*v_iter, spaceDim);
6532   } // for
6533   newCoordinates->allocatePoint();
6534 
6535   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
6536   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
6537     //std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl;
6538     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
6539   } // for
6540   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
6541   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
6542     //std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl;
6543     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
6544   } // for
6545 
6546   refiner.setCoordsNewVertices(newCoordinates, coordinates);
6547 
6548   // Create sensored depth
6549   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
6550   assert(!censoredLabel.isNull());
6551 
6552   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
6553 
6554   newSieve->roots(depthVisitor);
6555   while(depthVisitor.isModified()) {
6556     // FIX: Avoid the copy here somehow by fixing the traversal
6557     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
6558 
6559     depthVisitor.clear();
6560     newSieve->support(modifiedPoints, depthVisitor);
6561   } // while
6562   // Stratify refined mesh
6563   // Calculate new point SF
6564   _calcNewOverlap(newMesh, mesh, refiner);
6565   // Calculate new labels
6566   _createLabels(newMesh, mesh, refiner);
6567 #endif
6568   PetscFunctionReturn(0);
6569 }
6570 
6571 #undef __FUNCT__
6572 #define __FUNCT__ "DMPlexSetRefinementUniform"
6573 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6574 {
6575   DM_Plex *mesh = (DM_Plex *) dm->data;
6576 
6577   PetscFunctionBegin;
6578   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6579   mesh->refinementUniform = refinementUniform;
6580   PetscFunctionReturn(0);
6581 }
6582 
6583 #undef __FUNCT__
6584 #define __FUNCT__ "DMPlexGetRefinementUniform"
6585 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6586 {
6587   DM_Plex *mesh = (DM_Plex *) dm->data;
6588 
6589   PetscFunctionBegin;
6590   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6591   PetscValidPointer(refinementUniform,  2);
6592   *refinementUniform = mesh->refinementUniform;
6593   PetscFunctionReturn(0);
6594 }
6595 
6596 #undef __FUNCT__
6597 #define __FUNCT__ "DMPlexSetRefinementLimit"
6598 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6599 {
6600   DM_Plex *mesh = (DM_Plex *) dm->data;
6601 
6602   PetscFunctionBegin;
6603   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6604   mesh->refinementLimit = refinementLimit;
6605   PetscFunctionReturn(0);
6606 }
6607 
6608 #undef __FUNCT__
6609 #define __FUNCT__ "DMPlexGetRefinementLimit"
6610 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6611 {
6612   DM_Plex *mesh = (DM_Plex *) dm->data;
6613 
6614   PetscFunctionBegin;
6615   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6616   PetscValidPointer(refinementLimit,  2);
6617   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6618   *refinementLimit = mesh->refinementLimit;
6619   PetscFunctionReturn(0);
6620 }
6621 
6622 #undef __FUNCT__
6623 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
6624 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
6625 {
6626   PetscInt       dim, cStart, coneSize;
6627   PetscErrorCode ierr;
6628 
6629   PetscFunctionBegin;
6630   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6631   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
6632   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6633   switch(dim) {
6634   case 2:
6635     switch(coneSize) {
6636     case 3:
6637       *cellRefiner = 1;break;
6638     case 4:
6639       *cellRefiner = 2;break;
6640     default:
6641       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6642     }
6643     break;
6644   default:
6645     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6646   }
6647   PetscFunctionReturn(0);
6648 }
6649 
6650 #undef __FUNCT__
6651 #define __FUNCT__ "DMRefine_Plex"
6652 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
6653 {
6654   PetscReal      refinementLimit;
6655   PetscInt       dim, cStart, cEnd;
6656   char           genname[1024], *name = PETSC_NULL;
6657   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
6658   PetscErrorCode ierr;
6659 
6660   PetscFunctionBegin;
6661   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
6662   if (isUniform) {
6663     CellRefiner cellRefiner;
6664 
6665     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
6666     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
6667     PetscFunctionReturn(0);
6668   }
6669   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
6670   if (refinementLimit == 0.0) PetscFunctionReturn(0);
6671   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6672   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6673   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
6674   if (flg) {name = genname;}
6675   if (name) {
6676     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
6677     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
6678     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
6679   }
6680   switch(dim) {
6681   case 2:
6682     if (!name || isTriangle) {
6683 #ifdef PETSC_HAVE_TRIANGLE
6684       double  *maxVolumes;
6685       PetscInt c;
6686 
6687       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
6688       for (c = 0; c < cEnd-cStart; ++c) {
6689         maxVolumes[c] = refinementLimit;
6690       }
6691       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6692 #else
6693       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
6694 #endif
6695     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
6696     break;
6697   case 3:
6698     if (!name || isCTetgen) {
6699 #ifdef PETSC_HAVE_CTETGEN
6700       PetscReal *maxVolumes;
6701       PetscInt   c;
6702 
6703       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
6704       for (c = 0; c < cEnd-cStart; ++c) {
6705         maxVolumes[c] = refinementLimit;
6706       }
6707       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6708 #else
6709       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
6710 #endif
6711     } else if (isTetgen) {
6712 #ifdef PETSC_HAVE_TETGEN
6713       double  *maxVolumes;
6714       PetscInt c;
6715 
6716       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
6717       for (c = 0; c < cEnd-cStart; ++c) {
6718         maxVolumes[c] = refinementLimit;
6719       }
6720       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6721 #else
6722       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
6723 #endif
6724     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
6725     break;
6726   default:
6727     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
6728   }
6729   PetscFunctionReturn(0);
6730 }
6731 
6732 #undef __FUNCT__
6733 #define __FUNCT__ "DMPlexGetDepth"
6734 /*@
6735   DMPlexGetDepth - get the number of strata
6736 
6737   Not Collective
6738 
6739   Input Parameters:
6740 . dm           - The DMPlex object
6741 
6742   Output Parameters:
6743 . depth - number of strata
6744 
6745   Level: developer
6746 
6747   Notes:
6748   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
6749 
6750 .keywords: mesh, points
6751 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
6752 @*/
6753 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
6754 {
6755   PetscInt       d;
6756   PetscErrorCode ierr;
6757 
6758   PetscFunctionBegin;
6759   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6760   PetscValidPointer(depth, 2);
6761   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
6762   *depth = d-1;
6763   PetscFunctionReturn(0);
6764 }
6765 
6766 #undef __FUNCT__
6767 #define __FUNCT__ "DMPlexGetDepthStratum"
6768 /*@
6769   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
6770 
6771   Not Collective
6772 
6773   Input Parameters:
6774 + dm           - The DMPlex object
6775 - stratumValue - The requested depth
6776 
6777   Output Parameters:
6778 + start - The first point at this depth
6779 - end   - One beyond the last point at this depth
6780 
6781   Level: developer
6782 
6783 .keywords: mesh, points
6784 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
6785 @*/
6786 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) {
6787   DM_Plex    *mesh = (DM_Plex *) dm->data;
6788   DMLabel        next = mesh->labels;
6789   PetscBool      flg  = PETSC_FALSE;
6790   PetscInt       depth;
6791   PetscErrorCode ierr;
6792 
6793   PetscFunctionBegin;
6794   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6795   if (stratumValue < 0) {
6796     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6797     PetscFunctionReturn(0);
6798   } else {
6799     PetscInt pStart, pEnd;
6800 
6801     if (start) {*start = 0;}
6802     if (end)   {*end   = 0;}
6803     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6804     if (pStart == pEnd) {PetscFunctionReturn(0);}
6805   }
6806   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
6807   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6808   /* We should have a generic GetLabel() and a Label class */
6809   while(next) {
6810     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
6811     if (flg) break;
6812     next = next->next;
6813   }
6814   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6815   depth = stratumValue;
6816   if ((depth < 0) || (depth >= next->numStrata)) {
6817     if (start) {*start = 0;}
6818     if (end)   {*end   = 0;}
6819   } else {
6820     if (start) {*start = next->points[next->stratumOffsets[depth]];}
6821     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
6822   }
6823   PetscFunctionReturn(0);
6824 }
6825 
6826 #undef __FUNCT__
6827 #define __FUNCT__ "DMPlexGetHeightStratum"
6828 /*@
6829   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
6830 
6831   Not Collective
6832 
6833   Input Parameters:
6834 + dm           - The DMPlex object
6835 - stratumValue - The requested height
6836 
6837   Output Parameters:
6838 + start - The first point at this height
6839 - end   - One beyond the last point at this height
6840 
6841   Level: developer
6842 
6843 .keywords: mesh, points
6844 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
6845 @*/
6846 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) {
6847   DM_Plex    *mesh = (DM_Plex *) dm->data;
6848   DMLabel        next = mesh->labels;
6849   PetscBool      flg  = PETSC_FALSE;
6850   PetscInt       depth;
6851   PetscErrorCode ierr;
6852 
6853   PetscFunctionBegin;
6854   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6855   if (stratumValue < 0) {
6856     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6857   } else {
6858     PetscInt pStart, pEnd;
6859 
6860     if (start) {*start = 0;}
6861     if (end)   {*end   = 0;}
6862     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6863     if (pStart == pEnd) {PetscFunctionReturn(0);}
6864   }
6865   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
6866   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6867   /* We should have a generic GetLabel() and a Label class */
6868   while(next) {
6869     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
6870     if (flg) break;
6871     next = next->next;
6872   }
6873   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6874   depth = next->stratumValues[next->numStrata-1] - stratumValue;
6875   if ((depth < 0) || (depth >= next->numStrata)) {
6876     if (start) {*start = 0;}
6877     if (end)   {*end   = 0;}
6878   } else {
6879     if (start) {*start = next->points[next->stratumOffsets[depth]];}
6880     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
6881   }
6882   PetscFunctionReturn(0);
6883 }
6884 
6885 #undef __FUNCT__
6886 #define __FUNCT__ "DMPlexCreateSectionInitial"
6887 /* Set the number of dof on each point and separate by fields */
6888 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section) {
6889   PetscInt      *numDofTot;
6890   PetscInt       pStart = 0, pEnd = 0;
6891   PetscInt       p, d, f;
6892   PetscErrorCode ierr;
6893 
6894   PetscFunctionBegin;
6895   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
6896   for(d = 0; d <= dim; ++d) {
6897     numDofTot[d] = 0;
6898     for(f = 0; f < numFields; ++f) {
6899       numDofTot[d] += numDof[f*(dim+1)+d];
6900     }
6901   }
6902   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
6903   if (numFields > 0) {
6904     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
6905     if (numComp) {
6906       for(f = 0; f < numFields; ++f) {
6907         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
6908       }
6909     }
6910   }
6911   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6912   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
6913   for(d = 0; d <= dim; ++d) {
6914     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
6915     for(p = pStart; p < pEnd; ++p) {
6916       for(f = 0; f < numFields; ++f) {
6917         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
6918       }
6919       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
6920     }
6921   }
6922   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
6923   PetscFunctionReturn(0);
6924 }
6925 
6926 #undef __FUNCT__
6927 #define __FUNCT__ "DMPlexCreateSectionBCDof"
6928 /* Set the number of dof on each point and separate by fields
6929    If constDof is PETSC_DETERMINE, constrain every dof on the point
6930 */
6931 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section) {
6932   PetscInt       numFields;
6933   PetscInt       bc;
6934   PetscErrorCode ierr;
6935 
6936   PetscFunctionBegin;
6937   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6938   for (bc = 0; bc < numBC; ++bc) {
6939     PetscInt        field = 0;
6940     const PetscInt *idx;
6941     PetscInt        n, i;
6942 
6943     if (numFields) {field = bcField[bc];}
6944     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
6945     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6946     for (i = 0; i < n; ++i) {
6947       const PetscInt p = idx[i];
6948       PetscInt       numConst = constDof;
6949 
6950       /* Constrain every dof on the point */
6951       if (numConst < 0) {
6952         if (numFields) {
6953           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
6954         } else {
6955           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
6956         }
6957       }
6958       if (numFields) {
6959         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
6960       }
6961       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
6962     }
6963     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6964   }
6965   PetscFunctionReturn(0);
6966 }
6967 
6968 #undef __FUNCT__
6969 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
6970 /* Set the constrained indices on each point and separate by fields */
6971 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section) {
6972   PetscInt      *maxConstraints;
6973   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
6974   PetscErrorCode ierr;
6975 
6976   PetscFunctionBegin;
6977   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6978   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6979   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
6980   for(f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
6981   for(p = pStart; p < pEnd; ++p) {
6982     PetscInt cdof;
6983 
6984     if (numFields) {
6985       for(f = 0; f < numFields; ++f) {
6986         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
6987         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
6988       }
6989     } else {
6990       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6991       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
6992     }
6993   }
6994   for (f = 0; f < numFields; ++f) {
6995     maxConstraints[numFields] += maxConstraints[f];
6996   }
6997   if (maxConstraints[numFields]) {
6998     PetscInt *indices;
6999 
7000     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7001     for (p = pStart; p < pEnd; ++p) {
7002       PetscInt cdof, d;
7003 
7004       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7005       if (cdof) {
7006         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7007         if (numFields) {
7008           PetscInt numConst = 0, foff = 0;
7009 
7010           for (f = 0; f < numFields; ++f) {
7011             PetscInt cfdof, fdof;
7012 
7013             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7014             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7015             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7016             for(d = 0; d < cfdof; ++d) {
7017               indices[numConst+d] = d;
7018             }
7019             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7020             for(d = 0; d < cfdof; ++d) {
7021               indices[numConst+d] += foff;
7022             }
7023             numConst += cfdof;
7024             foff     += fdof;
7025           }
7026           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7027         } else {
7028           for (d = 0; d < cdof; ++d) {
7029             indices[d] = d;
7030           }
7031         }
7032         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7033       }
7034     }
7035     ierr = PetscFree(indices);CHKERRQ(ierr);
7036   }
7037   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7038   PetscFunctionReturn(0);
7039 }
7040 
7041 #undef __FUNCT__
7042 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7043 /* Set the constrained field indices on each point */
7044 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section) {
7045   const PetscInt *points, *indices;
7046   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7047   PetscErrorCode  ierr;
7048 
7049   PetscFunctionBegin;
7050   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7051   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7052 
7053   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7054   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7055   if (!constraintIndices) {
7056     PetscInt *idx, i;
7057 
7058     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7059     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7060     for(i = 0; i < maxDof; ++i) {idx[i] = i;}
7061     for(p = 0; p < numPoints; ++p) {
7062       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7063     }
7064     ierr = PetscFree(idx);CHKERRQ(ierr);
7065   } else {
7066     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7067     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7068     for(p = 0; p < numPoints; ++p) {
7069       PetscInt fcdof;
7070 
7071       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7072       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);
7073       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7074     }
7075     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7076   }
7077   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7078   PetscFunctionReturn(0);
7079 }
7080 
7081 #undef __FUNCT__
7082 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7083 /* Set the constrained indices on each point and separate by fields */
7084 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section) {
7085   PetscInt      *indices;
7086   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7087   PetscErrorCode ierr;
7088 
7089   PetscFunctionBegin;
7090   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7091   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7092   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7093   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7094   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7095   for (p = pStart; p < pEnd; ++p) {
7096     PetscInt cdof, d;
7097 
7098     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7099     if (cdof) {
7100       PetscInt numConst = 0, foff = 0;
7101 
7102       for (f = 0; f < numFields; ++f) {
7103         const PetscInt *fcind;
7104         PetscInt        fdof, fcdof;
7105 
7106         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7107         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7108         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7109         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7110         for(d = 0; d < fcdof; ++d) {
7111           indices[numConst+d] = fcind[d]+foff;
7112         }
7113         foff     += fdof;
7114         numConst += fcdof;
7115       }
7116       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7117       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7118     }
7119   }
7120   ierr = PetscFree(indices);CHKERRQ(ierr);
7121   PetscFunctionReturn(0);
7122 }
7123 
7124 #undef __FUNCT__
7125 #define __FUNCT__ "DMPlexCreateSection"
7126 /*@C
7127   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7128 
7129   Not Collective
7130 
7131   Input Parameters:
7132 + dm        - The DMPlex object
7133 . dim       - The spatial dimension of the problem
7134 . numFields - The number of fields in the problem
7135 . numComp   - An array of size numFields that holds the number of components for each field
7136 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7137 . numBC     - The number of boundary conditions
7138 . bcField   - An array of size numBC giving the field number for each boundry condition
7139 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7140 
7141   Output Parameter:
7142 . section - The PetscSection object
7143 
7144   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
7145   nubmer of dof for field 0 on each edge.
7146 
7147   Level: developer
7148 
7149 .keywords: mesh, elements
7150 .seealso: DMPlexCreate(), PetscSectionCreate()
7151 @*/
7152 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section) {
7153   PetscErrorCode ierr;
7154 
7155   PetscFunctionBegin;
7156   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7157   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7158   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7159   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7160   {
7161     PetscBool view = PETSC_FALSE;
7162 
7163     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7164     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7165   }
7166   PetscFunctionReturn(0);
7167 }
7168 
7169 #undef __FUNCT__
7170 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7171 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) {
7172   PetscSection   section;
7173   PetscErrorCode ierr;
7174 
7175   PetscFunctionBegin;
7176   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7177   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
7178   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7179   PetscFunctionReturn(0);
7180 }
7181 
7182 #undef __FUNCT__
7183 #define __FUNCT__ "DMPlexGetCoordinateSection"
7184 /*@
7185   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7186 
7187   Not Collective
7188 
7189   Input Parameter:
7190 . dm - The DMPlex object
7191 
7192   Output Parameter:
7193 . section - The PetscSection object
7194 
7195   Level: intermediate
7196 
7197 .keywords: mesh, coordinates
7198 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7199 @*/
7200 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section) {
7201   DM cdm;
7202   PetscErrorCode ierr;
7203 
7204   PetscFunctionBegin;
7205   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7206   PetscValidPointer(section, 2);
7207   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7208   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7209   PetscFunctionReturn(0);
7210 }
7211 
7212 #undef __FUNCT__
7213 #define __FUNCT__ "DMPlexSetCoordinateSection"
7214 /*@
7215   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7216 
7217   Not Collective
7218 
7219   Input Parameters:
7220 + dm      - The DMPlex object
7221 - section - The PetscSection object
7222 
7223   Level: intermediate
7224 
7225 .keywords: mesh, coordinates
7226 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7227 @*/
7228 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section) {
7229   DM             cdm;
7230   PetscErrorCode ierr;
7231 
7232   PetscFunctionBegin;
7233   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7234   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7235   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7236   PetscFunctionReturn(0);
7237 }
7238 
7239 #undef __FUNCT__
7240 #define __FUNCT__ "DMPlexGetConeSection"
7241 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) {
7242   DM_Plex *mesh = (DM_Plex *) dm->data;
7243 
7244   PetscFunctionBegin;
7245   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7246   if (section) *section = mesh->coneSection;
7247   PetscFunctionReturn(0);
7248 }
7249 
7250 #undef __FUNCT__
7251 #define __FUNCT__ "DMPlexGetCones"
7252 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) {
7253   DM_Plex *mesh = (DM_Plex *) dm->data;
7254 
7255   PetscFunctionBegin;
7256   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7257   if (cones) *cones = mesh->cones;
7258   PetscFunctionReturn(0);
7259 }
7260 
7261 #undef __FUNCT__
7262 #define __FUNCT__ "DMPlexGetConeOrientations"
7263 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) {
7264   DM_Plex *mesh = (DM_Plex *) dm->data;
7265 
7266   PetscFunctionBegin;
7267   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7268   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7269   PetscFunctionReturn(0);
7270 }
7271 
7272 #undef __FUNCT__
7273 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7274 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7275 {
7276   const PetscInt embedDim = 2;
7277   PetscReal      v0[2], J[4], invJ[4], detJ;
7278   PetscErrorCode ierr;
7279 
7280   PetscFunctionBegin;
7281   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7282   PetscReal xi  = invJ[0*embedDim+0]*(point[0] - v0[0]) + invJ[0*embedDim+1]*(point[1] - v0[1]);
7283   PetscReal eta = invJ[1*embedDim+0]*(point[0] - v0[0]) + invJ[1*embedDim+1]*(point[1] - v0[1]);
7284 
7285   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
7286     *cell = c;
7287   } else {
7288     *cell = -1;
7289   }
7290   PetscFunctionReturn(0);
7291 }
7292 
7293 #undef __FUNCT__
7294 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7295 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7296 {
7297   PetscSection       coordSection;
7298   Vec                coordsLocal;
7299   const PetscScalar *coords;
7300   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7301   PetscInt           crossings = 0, f;
7302   PetscErrorCode     ierr;
7303 
7304   PetscFunctionBegin;
7305   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7306   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7307   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7308   for(f = 0; f < 4; ++f) {
7309     PetscReal x_i   = coords[faces[2*f+0]*2+0];
7310     PetscReal y_i   = coords[faces[2*f+0]*2+1];
7311     PetscReal x_j   = coords[faces[2*f+1]*2+0];
7312     PetscReal y_j   = coords[faces[2*f+1]*2+1];
7313     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7314     PetscBool cond1 = (x_i <= point[0]) && (point[0] < x_j) ? PETSC_TRUE : PETSC_FALSE;
7315     PetscBool cond2 = (x_j <= point[0]) && (point[0] < x_i) ? PETSC_TRUE : PETSC_FALSE;
7316     PetscBool above = (point[1] < slope * (point[0] - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7317     if ((cond1 || cond2)  && above) ++crossings;
7318   }
7319   if (crossings % 2) {
7320     *cell = c;
7321   } else {
7322     *cell = -1;
7323   }
7324   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7325   PetscFunctionReturn(0);
7326 }
7327 
7328 #undef __FUNCT__
7329 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7330 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7331 {
7332   const PetscInt embedDim = 3;
7333   PetscReal      v0[3], J[9], invJ[9], detJ;
7334   PetscErrorCode ierr;
7335 
7336   PetscFunctionBegin;
7337   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7338   PetscReal xi   = invJ[0*embedDim+0]*(point[0] - v0[0]) + invJ[0*embedDim+1]*(point[1] - v0[1]) + invJ[0*embedDim+2]*(point[2] - v0[2]);
7339   PetscReal eta  = invJ[1*embedDim+0]*(point[0] - v0[0]) + invJ[1*embedDim+1]*(point[1] - v0[1]) + invJ[1*embedDim+2]*(point[2] - v0[2]);
7340   PetscReal zeta = invJ[2*embedDim+0]*(point[0] - v0[0]) + invJ[2*embedDim+1]*(point[1] - v0[1]) + invJ[2*embedDim+2]*(point[2] - v0[2]);
7341 
7342   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
7343     *cell = c;
7344   } else {
7345     *cell = -1;
7346   }
7347   PetscFunctionReturn(0);
7348 }
7349 
7350 #undef __FUNCT__
7351 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7352 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7353 {
7354   PetscSection       coordSection;
7355   Vec                coordsLocal;
7356   const PetscScalar *coords;
7357   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7358                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7359   PetscBool          found     = PETSC_TRUE;
7360   PetscInt           f;
7361   PetscErrorCode     ierr;
7362 
7363   PetscFunctionBegin;
7364   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7365   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7366   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7367   for(f = 0; f < 6; ++f) {
7368     /* Check the point is under plane */
7369     /*   Get face normal */
7370     PetscReal v_i[3]    = {coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0],coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1],coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]};
7371     PetscReal v_j[3]    = {coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0],coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1],coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]};
7372     PetscReal normal[3] = {v_i[1]*v_j[2] - v_i[2]*v_j[1], v_i[2]*v_j[0] - v_i[0]*v_j[2], v_i[0]*v_j[1] - v_i[1]*v_j[0]};
7373     PetscReal pp[3]     = {coords[faces[f*4+0]*3+0] - point[0],coords[faces[f*4+0]*3+1] - point[1],coords[faces[f*4+0]*3+2] - point[2]};
7374     PetscReal dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7375     /* Check that projected point is in face (2D location problem) */
7376     if (dot < 0.0) {
7377       found = PETSC_FALSE;
7378       break;
7379     }
7380   }
7381   if (found) {
7382     *cell = c;
7383   } else {
7384     *cell = -1;
7385   }
7386   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7387   PetscFunctionReturn(0);
7388 }
7389 
7390 #undef __FUNCT__
7391 #define __FUNCT__ "DMLocatePoints_Plex"
7392 /*
7393  Need to implement using the guess
7394 */
7395 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7396 {
7397   PetscInt       cell = -1/*, guess = -1*/;
7398   PetscInt       bs, numPoints, p;
7399   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7400   PetscInt      *cells;
7401   PetscScalar   *a;
7402   PetscErrorCode ierr;
7403 
7404   PetscFunctionBegin;
7405   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7406   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7407   ierr = DMPlexGetVTKBounds(dm, &cMax, PETSC_NULL);CHKERRQ(ierr);
7408   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7409   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7410   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7411   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);
7412   numPoints /= bs;
7413   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7414   for(p = 0; p < numPoints; ++p) {
7415     const PetscScalar *point = &a[p*bs];
7416 
7417     switch(dim) {
7418     case 2:
7419       for(c = cStart; c < cEnd; ++c) {
7420         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7421         switch(coneSize) {
7422         case 3:
7423           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7424           break;
7425         case 4:
7426           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7427           break;
7428         default:
7429           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7430         }
7431         if (cell >= 0) break;
7432       }
7433       break;
7434     case 3:
7435       for(c = cStart; c < cEnd; ++c) {
7436         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7437         switch(coneSize) {
7438         case 4:
7439           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
7440           break;
7441         case 8:
7442           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
7443           break;
7444         default:
7445           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7446         }
7447         if (cell >= 0) break;
7448       }
7449       break;
7450     default:
7451       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
7452     }
7453     cells[p] = cell;
7454   }
7455   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
7456   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
7457   PetscFunctionReturn(0);
7458 }
7459 
7460 /******************************** FEM Support **********************************/
7461 
7462 #undef __FUNCT__
7463 #define __FUNCT__ "DMPlexVecGetClosure"
7464 /*@C
7465   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
7466 
7467   Not collective
7468 
7469   Input Parameters:
7470 + dm - The DM
7471 . section - The section describing the layout in v, or PETSC_NULL to use the default section
7472 . v - The local vector
7473 - point - The sieve point in the DM
7474 
7475   Output Parameters:
7476 + csize - The number of values in the closure, or PETSC_NULL
7477 - values - The array of values, which is a borrowed array and should not be freed
7478 
7479   Level: intermediate
7480 
7481 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7482 @*/
7483 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[]) {
7484   PetscScalar    *array, *vArray;
7485   PetscInt       *points = PETSC_NULL;
7486   PetscInt        offsets[32];
7487   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
7488   PetscErrorCode  ierr;
7489 
7490   PetscFunctionBegin;
7491   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7492   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7493   if (!section) {
7494     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7495   }
7496   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7497   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7498   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7499   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7500   /* Compress out points not in the section */
7501   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7502   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7503     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7504       points[q*2]   = points[p];
7505       points[q*2+1] = points[p+1];
7506       ++q;
7507     }
7508   }
7509   numPoints = q;
7510   for (p = 0, size = 0; p < numPoints*2; p += 2) {
7511     PetscInt dof, fdof;
7512 
7513     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7514     for (f = 0; f < numFields; ++f) {
7515       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7516       offsets[f+1] += fdof;
7517     }
7518     size += dof;
7519   }
7520   for (f = 1; f < numFields; ++f) {
7521     offsets[f+1] += offsets[f];
7522   }
7523   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
7524   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
7525   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
7526   for (p = 0; p < numPoints*2; p += 2) {
7527     PetscInt     o = points[p+1];
7528     PetscInt     dof, off, d;
7529     PetscScalar *varr;
7530 
7531     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7532     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
7533     varr = &vArray[off];
7534     if (numFields) {
7535       PetscInt fdof, foff, fcomp, f, c;
7536 
7537       for (f = 0, foff = 0; f < numFields; ++f) {
7538         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7539         if (o >= 0) {
7540           for (d = 0; d < fdof; ++d, ++offsets[f]) {
7541             array[offsets[f]] = varr[foff+d];
7542           }
7543         } else {
7544           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7545           for (d = fdof/fcomp-1; d >= 0; --d) {
7546             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
7547               array[offsets[f]] = varr[foff+d*fcomp+c];
7548             }
7549           }
7550         }
7551         foff += fdof;
7552       }
7553     } else {
7554       if (o >= 0) {
7555         for (d = 0; d < dof; ++d, ++offsets[0]) {
7556           array[offsets[0]] = varr[d];
7557         }
7558       } else {
7559         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
7560           array[offsets[0]] = varr[d];
7561         }
7562       }
7563     }
7564   }
7565   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7566   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
7567   if (csize) *csize = size;
7568   *values = array;
7569   PetscFunctionReturn(0);
7570 }
7571 
7572 #undef __FUNCT__
7573 #define __FUNCT__ "DMPlexVecRestoreClosure"
7574 /*@C
7575   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
7576 
7577   Not collective
7578 
7579   Input Parameters:
7580 + dm - The DM
7581 . section - The section describing the layout in v, or PETSC_NULL to use the default section
7582 . v - The local vector
7583 . point - The sieve point in the DM
7584 . csize - The number of values in the closure, or PETSC_NULL
7585 - values - The array of values, which is a borrowed array and should not be freed
7586 
7587   Level: intermediate
7588 
7589 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7590 @*/
7591 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[]) {
7592   PetscInt        size = 0;
7593   PetscErrorCode  ierr;
7594 
7595   PetscFunctionBegin;
7596   /* Should work without recalculating size */
7597   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
7598   PetscFunctionReturn(0);
7599 }
7600 
7601 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
7602 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
7603 
7604 #undef __FUNCT__
7605 #define __FUNCT__ "updatePoint_private"
7606 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
7607 {
7608   PetscInt        cdof;  /* The number of constraints on this point */
7609   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7610   PetscScalar    *a;
7611   PetscInt        off, cind = 0, k;
7612   PetscErrorCode  ierr;
7613 
7614   PetscFunctionBegin;
7615   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7616   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7617   a    = &array[off];
7618   if (!cdof || setBC) {
7619     if (orientation >= 0) {
7620       for (k = 0; k < dof; ++k) {
7621         fuse(&a[k], values[k]);
7622       }
7623     } else {
7624       for (k = 0; k < dof; ++k) {
7625         fuse(&a[k], values[dof-k-1]);
7626       }
7627     }
7628   } else {
7629     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7630     if (orientation >= 0) {
7631       for (k = 0; k < dof; ++k) {
7632         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7633         fuse(&a[k], values[k]);
7634       }
7635     } else {
7636       for (k = 0; k < dof; ++k) {
7637         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7638         fuse(&a[k], values[dof-k-1]);
7639       }
7640     }
7641   }
7642   PetscFunctionReturn(0);
7643 }
7644 
7645 #undef __FUNCT__
7646 #define __FUNCT__ "updatePointFields_private"
7647 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[]) {
7648   PetscScalar   *a;
7649   PetscInt       numFields, off, foff, f;
7650   PetscErrorCode ierr;
7651 
7652   PetscFunctionBegin;
7653   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7654   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7655   a    = &array[off];
7656   for (f = 0, foff = 0; f < numFields; ++f) {
7657     PetscInt        fdof, fcomp, fcdof;
7658     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7659     PetscInt        cind = 0, k, c;
7660 
7661     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7662     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7663     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
7664     if (!fcdof || setBC) {
7665       if (orientation >= 0) {
7666         for (k = 0; k < fdof; ++k) {
7667           fuse(&a[foff+k], values[foffs[f]+k]);
7668         }
7669       } else {
7670         for (k = fdof/fcomp-1; k >= 0; --k) {
7671           for (c = 0; c < fcomp; ++c) {
7672             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7673           }
7674         }
7675       }
7676     } else {
7677       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7678       if (orientation >= 0) {
7679         for (k = 0; k < fdof; ++k) {
7680           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
7681           fuse(&a[foff+k], values[foffs[f]+k]);
7682         }
7683       } else {
7684         for (k = fdof/fcomp-1; k >= 0; --k) {
7685           for (c = 0; c < fcomp; ++c) {
7686             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
7687             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7688           }
7689         }
7690       }
7691     }
7692     foff     += fdof;
7693     foffs[f] += fdof;
7694   }
7695   PetscFunctionReturn(0);
7696 }
7697 
7698 #undef __FUNCT__
7699 #define __FUNCT__ "DMPlexVecSetClosure"
7700 /*@C
7701   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
7702 
7703   Not collective
7704 
7705   Input Parameters:
7706 + dm - The DM
7707 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
7708 . v - The local vector
7709 . point - The sieve point in the DM
7710 . values - The array of values, which is a borrowed array and should not be freed
7711 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7712 
7713   Level: intermediate
7714 
7715 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
7716 @*/
7717 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) {
7718   PetscScalar    *array;
7719   PetscInt       *points = PETSC_NULL;
7720   PetscInt        offsets[32];
7721   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
7722   PetscErrorCode  ierr;
7723 
7724   PetscFunctionBegin;
7725   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7726   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7727   if (!section) {
7728     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7729   }
7730   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7731   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7732   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7733   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7734   /* Compress out points not in the section */
7735   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7736   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7737     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7738       points[q*2]   = points[p];
7739       points[q*2+1] = points[p+1];
7740       ++q;
7741     }
7742   }
7743   numPoints = q;
7744   for (p = 0; p < numPoints*2; p += 2) {
7745     PetscInt fdof;
7746 
7747     for (f = 0; f < numFields; ++f) {
7748       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7749       offsets[f+1] += fdof;
7750     }
7751   }
7752   for (f = 1; f < numFields; ++f) {
7753     offsets[f+1] += offsets[f];
7754   }
7755   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
7756   if (numFields) {
7757     switch(mode) {
7758     case INSERT_VALUES:
7759       for (p = 0; p < numPoints*2; p += 2) {
7760         PetscInt o = points[p+1];
7761         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
7762       } break;
7763     case INSERT_ALL_VALUES:
7764       for (p = 0; p < numPoints*2; p += 2) {
7765         PetscInt o = points[p+1];
7766         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
7767       } break;
7768     case ADD_VALUES:
7769       for (p = 0; p < numPoints*2; p += 2) {
7770         PetscInt o = points[p+1];
7771         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
7772       } break;
7773     case ADD_ALL_VALUES:
7774       for (p = 0; p < numPoints*2; p += 2) {
7775         PetscInt o = points[p+1];
7776         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
7777       } break;
7778     default:
7779       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7780     }
7781   } else {
7782     switch(mode) {
7783     case INSERT_VALUES:
7784       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7785         PetscInt o = points[p+1];
7786         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7787         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
7788       } break;
7789     case INSERT_ALL_VALUES:
7790       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7791         PetscInt o = points[p+1];
7792         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7793         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
7794       } break;
7795     case ADD_VALUES:
7796       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7797         PetscInt o = points[p+1];
7798         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7799         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
7800       } break;
7801     case ADD_ALL_VALUES:
7802       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7803         PetscInt o = points[p+1];
7804         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7805         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
7806       } break;
7807     default:
7808       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7809     }
7810   }
7811   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7812   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
7813   PetscFunctionReturn(0);
7814 }
7815 
7816 #undef __FUNCT__
7817 #define __FUNCT__ "DMPlexPrintMatSetValues"
7818 PetscErrorCode DMPlexPrintMatSetValues(Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
7819 {
7820   PetscMPIInt    rank;
7821   PetscInt       i, j;
7822   PetscErrorCode ierr;
7823 
7824   PetscFunctionBegin;
7825   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
7826   ierr = PetscPrintf(PETSC_COMM_SELF, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
7827   for (i = 0; i < numIndices; i++) {
7828     ierr = PetscPrintf(PETSC_COMM_SELF, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
7829   }
7830   for (i = 0; i < numIndices; i++) {
7831     ierr = PetscPrintf(PETSC_COMM_SELF, "[%D]", rank);CHKERRQ(ierr);
7832     for (j = 0; j < numIndices; j++) {
7833 #ifdef PETSC_USE_COMPLEX
7834       ierr = PetscPrintf(PETSC_COMM_SELF, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
7835 #else
7836       ierr = PetscPrintf(PETSC_COMM_SELF, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
7837 #endif
7838     }
7839     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7840   }
7841   PetscFunctionReturn(0);
7842 }
7843 
7844 #undef __FUNCT__
7845 #define __FUNCT__ "indicesPoint_private"
7846 /* . off - The global offset of this point */
7847 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[]) {
7848   PetscInt        cdof;  /* The number of constraints on this point */
7849   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7850   PetscInt        cind = 0, k;
7851   PetscErrorCode  ierr;
7852 
7853   PetscFunctionBegin;
7854   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
7855   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7856   if (!cdof || setBC) {
7857     if (orientation >= 0) {
7858       for (k = 0; k < dof; ++k) {
7859         indices[k] = off+k;
7860       }
7861     } else {
7862       for (k = 0; k < dof; ++k) {
7863         indices[dof-k-1] = off+k;
7864       }
7865     }
7866   } else {
7867     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7868     if (orientation >= 0) {
7869       for (k = 0; k < dof; ++k) {
7870         if ((cind < cdof) && (k == cdofs[cind])) {
7871           /* Insert check for returning constrained indices */
7872           indices[k] = -(off+k+1);
7873           ++cind;
7874         } else {
7875           indices[k] = off+k-cind;
7876         }
7877       }
7878     } else {
7879       for (k = 0; k < dof; ++k) {
7880         if ((cind < cdof) && (k == cdofs[cind])) {
7881           /* Insert check for returning constrained indices */
7882           indices[dof-k-1] = -(off+k+1);
7883           ++cind;
7884         } else {
7885           indices[dof-k-1] = off+k-cind;
7886         }
7887       }
7888     }
7889   }
7890   PetscFunctionReturn(0);
7891 }
7892 
7893 #undef __FUNCT__
7894 #define __FUNCT__ "indicesPointFields_private"
7895 /* . off - The global offset of this point */
7896 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[]) {
7897   PetscInt       numFields, foff, f;
7898   PetscErrorCode ierr;
7899 
7900   PetscFunctionBegin;
7901   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7902   for (f = 0, foff = 0; f < numFields; ++f) {
7903     PetscInt        fdof, fcomp, cfdof;
7904     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7905     PetscInt        cind = 0, k, c;
7906 
7907     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7908     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7909     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
7910     if (!cfdof || setBC) {
7911       if (orientation >= 0) {
7912         for (k = 0; k < fdof; ++k) {
7913           indices[foffs[f]+k] = off+foff+k;
7914         }
7915       } else {
7916         for (k = fdof/fcomp-1; k >= 0; --k) {
7917           for (c = 0; c < fcomp; ++c) {
7918             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
7919           }
7920         }
7921       }
7922     } else {
7923       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7924       if (orientation >= 0) {
7925         for (k = 0; k < fdof; ++k) {
7926           if ((cind < cfdof) && (k == fcdofs[cind])) {
7927             indices[foffs[f]+k] = -(off+foff+k+1);
7928             ++cind;
7929           } else {
7930             indices[foffs[f]+k] = off+foff+k-cind;
7931           }
7932         }
7933       } else {
7934         for (k = fdof/fcomp-1; k >= 0; --k) {
7935           for (c = 0; c < fcomp; ++c) {
7936             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
7937               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
7938               ++cind;
7939             } else {
7940               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
7941             }
7942           }
7943         }
7944       }
7945     }
7946     foff     += fdof - cfdof;
7947     foffs[f] += fdof;
7948   }
7949   PetscFunctionReturn(0);
7950 }
7951 
7952 #undef __FUNCT__
7953 #define __FUNCT__ "DMPlexMatSetClosure"
7954 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
7955 {
7956   DM_Plex     *mesh   = (DM_Plex *) dm->data;
7957   PetscInt       *points = PETSC_NULL;
7958   PetscInt       *indices;
7959   PetscInt        offsets[32];
7960   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
7961   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
7962   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
7963   PetscErrorCode  ierr;
7964 
7965   PetscFunctionBegin;
7966   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7967   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
7968   if (useDefault) {
7969     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7970   }
7971   if (useGlobalDefault) {
7972     if (useDefault) {
7973       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
7974     } else {
7975       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7976     }
7977   }
7978   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7979   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7980   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7981   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7982   /* Compress out points not in the section */
7983   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7984   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7985     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7986       points[q*2]   = points[p];
7987       points[q*2+1] = points[p+1];
7988       ++q;
7989     }
7990   }
7991   numPoints = q;
7992   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
7993     PetscInt fdof;
7994 
7995     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7996     for (f = 0; f < numFields; ++f) {
7997       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7998       offsets[f+1] += fdof;
7999     }
8000     numIndices += dof;
8001   }
8002   for (f = 1; f < numFields; ++f) {
8003     offsets[f+1] += offsets[f];
8004   }
8005   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8006   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8007   if (numFields) {
8008     for (p = 0; p < numPoints*2; p += 2) {
8009       PetscInt o = points[p+1];
8010       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8011       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8012     }
8013   } else {
8014     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8015       PetscInt o = points[p+1];
8016       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8017       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8018     }
8019   }
8020   if (useGlobalDefault && !useDefault) {
8021     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8022   }
8023   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(A, point, numIndices, indices, values);CHKERRQ(ierr);}
8024   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8025   if (ierr) {
8026     PetscMPIInt    rank;
8027     PetscErrorCode ierr2;
8028 
8029     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8030     ierr2 = PetscPrintf(PETSC_COMM_SELF, "[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8031     ierr2 = DMPlexPrintMatSetValues(A, point, numIndices, indices, values);CHKERRQ(ierr2);
8032     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8033     CHKERRQ(ierr);
8034   }
8035   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8036   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8037   PetscFunctionReturn(0);
8038 }
8039 
8040 #undef __FUNCT__
8041 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8042 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8043 {
8044   PetscSection       coordSection;
8045   Vec                coordinates;
8046   const PetscScalar *coords;
8047   const PetscInt     dim = 2;
8048   PetscInt           d, f;
8049   PetscErrorCode     ierr;
8050 
8051   PetscFunctionBegin;
8052   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8053   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8054   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8055   if (v0) {
8056     for (d = 0; d < dim; d++) {
8057       v0[d] = PetscRealPart(coords[d]);
8058     }
8059   }
8060   if (J) {
8061     for (d = 0; d < dim; d++) {
8062       for (f = 0; f < dim; f++) {
8063         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8064       }
8065     }
8066     *detJ = J[0]*J[3] - J[1]*J[2];
8067 #if 0
8068     if (detJ < 0.0) {
8069       const PetscReal xLength = mesh->periodicity[0];
8070 
8071       if (xLength != 0.0) {
8072         PetscReal v0x = coords[0*dim+0];
8073 
8074         if (v0x == 0.0) {
8075           v0x = v0[0] = xLength;
8076         }
8077         for (f = 0; f < dim; f++) {
8078           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8079 
8080           J[0*dim+f] = 0.5*(px - v0x);
8081         }
8082       }
8083       detJ = J[0]*J[3] - J[1]*J[2];
8084     }
8085 #endif
8086     PetscLogFlops(8.0 + 3.0);
8087   }
8088   if (invJ) {
8089     const PetscReal invDet = 1.0/(*detJ);
8090 
8091     invJ[0] =  invDet*J[3];
8092     invJ[1] = -invDet*J[1];
8093     invJ[2] = -invDet*J[2];
8094     invJ[3] =  invDet*J[0];
8095     PetscLogFlops(5.0);
8096   }
8097   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8098   PetscFunctionReturn(0);
8099 }
8100 
8101 #undef __FUNCT__
8102 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8103 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8104 {
8105   PetscSection       coordSection;
8106   Vec                coordinates;
8107   const PetscScalar *coords;
8108   const PetscInt     dim = 2;
8109   PetscInt           d, f;
8110   PetscErrorCode     ierr;
8111 
8112   PetscFunctionBegin;
8113   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8114   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8115   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8116   if (v0) {
8117     for (d = 0; d < dim; d++) {
8118       v0[d] = PetscRealPart(coords[d]);
8119     }
8120   }
8121   if (J) {
8122     for (d = 0; d < dim; d++) {
8123       for (f = 0; f < dim; f++) {
8124         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8125       }
8126     }
8127     *detJ = J[0]*J[3] - J[1]*J[2];
8128     PetscLogFlops(8.0 + 3.0);
8129   }
8130   if (invJ) {
8131     const PetscReal invDet = 1.0/(*detJ);
8132 
8133     invJ[0] =  invDet*J[3];
8134     invJ[1] = -invDet*J[1];
8135     invJ[2] = -invDet*J[2];
8136     invJ[3] =  invDet*J[0];
8137     PetscLogFlops(5.0);
8138   }
8139   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8140   PetscFunctionReturn(0);
8141 }
8142 
8143 #undef __FUNCT__
8144 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8145 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8146 {
8147   PetscSection       coordSection;
8148   Vec                coordinates;
8149   const PetscScalar *coords;
8150   const PetscInt     dim = 3;
8151   PetscInt           d, f;
8152   PetscErrorCode     ierr;
8153 
8154   PetscFunctionBegin;
8155   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8156   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8157   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8158   if (v0) {
8159     for (d = 0; d < dim; d++) {
8160       v0[d] = PetscRealPart(coords[d]);
8161     }
8162   }
8163   if (J) {
8164     for (d = 0; d < dim; d++) {
8165       for (f = 0; f < dim; f++) {
8166         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8167       }
8168     }
8169     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8170     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8171              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8172              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8173     PetscLogFlops(18.0 + 12.0);
8174   }
8175   if (invJ) {
8176     const PetscReal invDet = -1.0/(*detJ);
8177 
8178     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8179     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8180     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8181     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8182     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8183     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8184     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8185     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8186     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8187     PetscLogFlops(37.0);
8188   }
8189   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8190   PetscFunctionReturn(0);
8191 }
8192 
8193 #undef __FUNCT__
8194 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8195 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8196 {
8197   PetscSection       coordSection;
8198   Vec                coordinates;
8199   const PetscScalar *coords;
8200   const PetscInt     dim = 3;
8201   PetscInt           d;
8202   PetscErrorCode     ierr;
8203 
8204   PetscFunctionBegin;
8205   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8206   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8207   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8208   if (v0) {
8209     for (d = 0; d < dim; d++) {
8210       v0[d] = PetscRealPart(coords[d]);
8211     }
8212   }
8213   if (J) {
8214     for (d = 0; d < dim; d++) {
8215       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8216       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8217       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8218     }
8219     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8220              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8221              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8222     PetscLogFlops(18.0 + 12.0);
8223   }
8224   if (invJ) {
8225     const PetscReal invDet = -1.0/(*detJ);
8226 
8227     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8228     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8229     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8230     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8231     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8232     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8233     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8234     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8235     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8236     PetscLogFlops(37.0);
8237   }
8238   *detJ *= 8.0;
8239   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8240   PetscFunctionReturn(0);
8241 }
8242 
8243 #undef __FUNCT__
8244 #define __FUNCT__ "DMPlexComputeCellGeometry"
8245 /*@C
8246   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8247 
8248   Collective on DM
8249 
8250   Input Arguments:
8251 + dm   - the DM
8252 - cell - the cell
8253 
8254   Output Arguments:
8255 + v0   - the translation part of this affine transform
8256 . J    - the Jacobian of the transform to the reference element
8257 . invJ - the inverse of the Jacobian
8258 - detJ - the Jacobian determinant
8259 
8260   Level: advanced
8261 
8262 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8263 @*/
8264 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ) {
8265   PetscInt       dim, maxConeSize;
8266   PetscErrorCode ierr;
8267 
8268   PetscFunctionBegin;
8269   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8270   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
8271   switch(dim) {
8272   case 2:
8273     switch(maxConeSize) {
8274     case 3:
8275       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8276       break;
8277     case 4:
8278       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8279       break;
8280     default:
8281       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of cell vertices %D for element geometry computation", maxConeSize);
8282     }
8283     break;
8284   case 3:
8285     switch(maxConeSize) {
8286     case 4:
8287       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8288       break;
8289     case 8:
8290       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8291       break;
8292     default:
8293       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of cell vertices %D for element geometry computation", maxConeSize);
8294     }
8295     break;
8296   default:
8297     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8298   }
8299   PetscFunctionReturn(0);
8300 }
8301 
8302 #undef __FUNCT__
8303 #define __FUNCT__ "DMPlexGetFaceOrientation"
8304 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented) {
8305   MPI_Comm       comm      = ((PetscObject) dm)->comm;
8306   PetscBool      posOrient = PETSC_FALSE;
8307   const PetscInt debug     = 0;
8308   PetscInt       cellDim, faceSize, f;
8309   PetscErrorCode ierr;
8310 
8311   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
8312   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
8313 
8314   if (cellDim == numCorners-1) {
8315     /* Simplices */
8316     faceSize  = numCorners-1;
8317     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
8318   } else if (cellDim == 1 && numCorners == 3) {
8319     /* Quadratic line */
8320     faceSize  = 1;
8321     posOrient = PETSC_TRUE;
8322   } else if (cellDim == 2 && numCorners == 4) {
8323     /* Quads */
8324     faceSize  = 2;
8325     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
8326       posOrient = PETSC_TRUE;
8327     } else if ((indices[0] == 3) && (indices[1] == 0)) {
8328       posOrient = PETSC_TRUE;
8329     } else {
8330       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
8331         posOrient = PETSC_FALSE;
8332       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
8333     }
8334   } else if (cellDim == 2 && numCorners == 6) {
8335     /* Quadratic triangle (I hate this) */
8336     /* Edges are determined by the first 2 vertices (corners of edges) */
8337     const PetscInt faceSizeTri = 3;
8338     PetscInt  sortedIndices[3], i, iFace;
8339     PetscBool found = PETSC_FALSE;
8340     PetscInt  faceVerticesTriSorted[9] = {
8341       0, 3,  4, /* bottom */
8342       1, 4,  5, /* right */
8343       2, 3,  5, /* left */
8344     };
8345     PetscInt  faceVerticesTri[9] = {
8346       0, 3,  4, /* bottom */
8347       1, 4,  5, /* right */
8348       2, 5,  3, /* left */
8349     };
8350 
8351     faceSize = faceSizeTri;
8352     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
8353     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
8354     for (iFace = 0; iFace < 3; ++iFace) {
8355       const PetscInt ii = iFace*faceSizeTri;
8356       PetscInt       fVertex, cVertex;
8357 
8358       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
8359           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
8360         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
8361           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
8362             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
8363               faceVertices[fVertex] = origVertices[cVertex];
8364               break;
8365             }
8366           }
8367         }
8368         found = PETSC_TRUE;
8369         break;
8370       }
8371     }
8372     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
8373     if (posOriented) {*posOriented = PETSC_TRUE;}
8374     PetscFunctionReturn(0);
8375   } else if (cellDim == 2 && numCorners == 9) {
8376     /* Quadratic quad (I hate this) */
8377     /* Edges are determined by the first 2 vertices (corners of edges) */
8378     const PetscInt faceSizeQuad = 3;
8379     PetscInt  sortedIndices[3], i, iFace;
8380     PetscBool found = PETSC_FALSE;
8381     PetscInt  faceVerticesQuadSorted[12] = {
8382       0, 1,  4, /* bottom */
8383       1, 2,  5, /* right */
8384       2, 3,  6, /* top */
8385       0, 3,  7, /* left */
8386     };
8387     PetscInt  faceVerticesQuad[12] = {
8388       0, 1,  4, /* bottom */
8389       1, 2,  5, /* right */
8390       2, 3,  6, /* top */
8391       3, 0,  7, /* left */
8392     };
8393 
8394     faceSize = faceSizeQuad;
8395     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
8396     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
8397     for (iFace = 0; iFace < 4; ++iFace) {
8398       const PetscInt ii = iFace*faceSizeQuad;
8399       PetscInt       fVertex, cVertex;
8400 
8401       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
8402           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
8403         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
8404           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
8405             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
8406               faceVertices[fVertex] = origVertices[cVertex];
8407               break;
8408             }
8409           }
8410         }
8411         found = PETSC_TRUE;
8412         break;
8413       }
8414     }
8415     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
8416     if (posOriented) {*posOriented = PETSC_TRUE;}
8417     PetscFunctionReturn(0);
8418   } else if (cellDim == 3 && numCorners == 8) {
8419     /* Hexes
8420        A hex is two oriented quads with the normal of the first
8421        pointing up at the second.
8422 
8423           7---6
8424          /|  /|
8425         4---5 |
8426         | 3-|-2
8427         |/  |/
8428         0---1
8429 
8430         Faces are determined by the first 4 vertices (corners of faces) */
8431     const PetscInt faceSizeHex = 4;
8432     PetscInt  sortedIndices[4], i, iFace;
8433     PetscBool found = PETSC_FALSE;
8434     PetscInt faceVerticesHexSorted[24] = {
8435       0, 1, 2, 3,  /* bottom */
8436       4, 5, 6, 7,  /* top */
8437       0, 1, 4, 5,  /* front */
8438       1, 2, 5, 6,  /* right */
8439       2, 3, 6, 7,  /* back */
8440       0, 3, 4, 7,  /* left */
8441     };
8442     PetscInt faceVerticesHex[24] = {
8443       3, 2, 1, 0,  /* bottom */
8444       4, 5, 6, 7,  /* top */
8445       0, 1, 5, 4,  /* front */
8446       1, 2, 6, 5,  /* right */
8447       2, 3, 7, 6,  /* back */
8448       3, 0, 4, 7,  /* left */
8449     };
8450 
8451     faceSize = faceSizeHex;
8452     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
8453     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
8454     for (iFace = 0; iFace < 6; ++iFace) {
8455       const PetscInt ii = iFace*faceSizeHex;
8456       PetscInt       fVertex, cVertex;
8457 
8458       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
8459           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
8460           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
8461           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
8462         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
8463           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
8464             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
8465               faceVertices[fVertex] = origVertices[cVertex];
8466               break;
8467             }
8468           }
8469         }
8470         found = PETSC_TRUE;
8471         break;
8472       }
8473     }
8474     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
8475     if (posOriented) {*posOriented = PETSC_TRUE;}
8476     PetscFunctionReturn(0);
8477   } else if (cellDim == 3 && numCorners == 10) {
8478     /* Quadratic tet */
8479     /* Faces are determined by the first 3 vertices (corners of faces) */
8480     const PetscInt faceSizeTet = 6;
8481     PetscInt  sortedIndices[6], i, iFace;
8482     PetscBool found = PETSC_FALSE;
8483     PetscInt faceVerticesTetSorted[24] = {
8484       0, 1, 2,  6, 7, 8, /* bottom */
8485       0, 3, 4,  6, 7, 9,  /* front */
8486       1, 4, 5,  7, 8, 9,  /* right */
8487       2, 3, 5,  6, 8, 9,  /* left */
8488     };
8489     PetscInt faceVerticesTet[24] = {
8490       0, 1, 2,  6, 7, 8, /* bottom */
8491       0, 4, 3,  6, 7, 9,  /* front */
8492       1, 5, 4,  7, 8, 9,  /* right */
8493       2, 3, 5,  8, 6, 9,  /* left */
8494     };
8495 
8496     faceSize = faceSizeTet;
8497     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
8498     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
8499     for (iFace=0; iFace < 4; ++iFace) {
8500       const PetscInt ii = iFace*faceSizeTet;
8501       PetscInt       fVertex, cVertex;
8502 
8503       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
8504           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
8505           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
8506           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
8507         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
8508           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
8509             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
8510               faceVertices[fVertex] = origVertices[cVertex];
8511               break;
8512             }
8513           }
8514         }
8515         found = PETSC_TRUE;
8516         break;
8517       }
8518     }
8519     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
8520     if (posOriented) {*posOriented = PETSC_TRUE;}
8521     PetscFunctionReturn(0);
8522   } else if (cellDim == 3 && numCorners == 27) {
8523     /* Quadratic hexes (I hate this)
8524        A hex is two oriented quads with the normal of the first
8525        pointing up at the second.
8526 
8527          7---6
8528         /|  /|
8529        4---5 |
8530        | 3-|-2
8531        |/  |/
8532        0---1
8533 
8534        Faces are determined by the first 4 vertices (corners of faces) */
8535     const PetscInt faceSizeQuadHex = 9;
8536     PetscInt  sortedIndices[9], i, iFace;
8537     PetscBool found = PETSC_FALSE;
8538     PetscInt faceVerticesQuadHexSorted[54] = {
8539       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
8540       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
8541       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
8542       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
8543       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
8544       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
8545     };
8546     PetscInt faceVerticesQuadHex[54] = {
8547       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
8548       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
8549       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
8550       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
8551       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
8552       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
8553     };
8554 
8555     faceSize = faceSizeQuadHex;
8556     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
8557     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
8558     for (iFace = 0; iFace < 6; ++iFace) {
8559       const PetscInt ii = iFace*faceSizeQuadHex;
8560       PetscInt       fVertex, cVertex;
8561 
8562       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
8563           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
8564           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
8565           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
8566         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
8567           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
8568             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
8569               faceVertices[fVertex] = origVertices[cVertex];
8570               break;
8571             }
8572           }
8573         }
8574         found = PETSC_TRUE;
8575         break;
8576       }
8577     }
8578     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
8579     if (posOriented) {*posOriented = PETSC_TRUE;}
8580     PetscFunctionReturn(0);
8581   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
8582   if (!posOrient) {
8583     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
8584     for (f = 0; f < faceSize; ++f) {
8585       faceVertices[f] = origVertices[faceSize-1 - f];
8586     }
8587   } else {
8588     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
8589     for (f = 0; f < faceSize; ++f) {
8590       faceVertices[f] = origVertices[f];
8591     }
8592   }
8593   if (posOriented) {*posOriented = posOrient;}
8594   PetscFunctionReturn(0);
8595 }
8596 
8597 #undef __FUNCT__
8598 #define __FUNCT__ "DMPlexGetOrientedFace"
8599 /*
8600     Given a cell and a face, as a set of vertices,
8601       return the oriented face, as a set of vertices, in faceVertices
8602     The orientation is such that the face normal points out of the cell
8603 */
8604 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
8605 {
8606   const PetscInt *cone = PETSC_NULL;
8607   PetscInt        coneSize, v, f, v2;
8608   PetscInt        oppositeVertex = -1;
8609   PetscErrorCode  ierr;
8610 
8611   PetscFunctionBegin;
8612   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8613   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
8614   for (v = 0, v2 = 0; v < coneSize; ++v) {
8615     PetscBool found  = PETSC_FALSE;
8616 
8617     for (f = 0; f < faceSize; ++f) {
8618       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
8619     }
8620     if (found) {
8621       indices[v2]      = v;
8622       origVertices[v2] = cone[v];
8623       ++v2;
8624     } else {
8625       oppositeVertex = v;
8626     }
8627   }
8628   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
8629   PetscFunctionReturn(0);
8630 }
8631 
8632 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8633 {
8634   switch(i) {
8635   case 0:
8636     switch(j) {
8637     case 0: return 0;
8638     case 1:
8639       switch(k) {
8640       case 0: return 0;
8641       case 1: return 0;
8642       case 2: return 1;
8643       }
8644     case 2:
8645       switch(k) {
8646       case 0: return 0;
8647       case 1: return -1;
8648       case 2: return 0;
8649       }
8650     }
8651   case 1:
8652     switch(j) {
8653     case 0:
8654       switch(k) {
8655       case 0: return 0;
8656       case 1: return 0;
8657       case 2: return -1;
8658       }
8659     case 1: return 0;
8660     case 2:
8661       switch(k) {
8662       case 0: return 1;
8663       case 1: return 0;
8664       case 2: return 0;
8665       }
8666     }
8667   case 2:
8668     switch(j) {
8669     case 0:
8670       switch(k) {
8671       case 0: return 0;
8672       case 1: return 1;
8673       case 2: return 0;
8674       }
8675     case 1:
8676       switch(k) {
8677       case 0: return -1;
8678       case 1: return 0;
8679       case 2: return 0;
8680       }
8681     case 2: return 0;
8682     }
8683   }
8684   return 0;
8685 }
8686 
8687 #undef __FUNCT__
8688 #define __FUNCT__ "DMPlexCreateRigidBody"
8689 /*@C
8690   DMPlexCreateRigidBody - create rigid body modes from coordinates
8691 
8692   Collective on DM
8693 
8694   Input Arguments:
8695 + dm - the DM
8696 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
8697 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
8698 
8699   Output Argument:
8700 . sp - the null space
8701 
8702   Note: This is necessary to take account of Dirichlet conditions on the displacements
8703 
8704   Level: advanced
8705 
8706 .seealso: MatNullSpaceCreate()
8707 @*/
8708 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8709 {
8710   MPI_Comm       comm = ((PetscObject) dm)->comm;
8711   Vec            coordinates, localMode, mode[6];
8712   PetscSection   coordSection;
8713   PetscScalar   *coords;
8714   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8715   PetscErrorCode ierr;
8716 
8717   PetscFunctionBegin;
8718   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8719   if (dim == 1) {
8720     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
8721     PetscFunctionReturn(0);
8722   }
8723   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8724   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8725   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8726   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8727   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8728   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8729   m    = (dim*(dim+1))/2;
8730   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8731   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8732   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8733   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8734   /* Assume P1 */
8735   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8736   for (d = 0; d < dim; ++d) {
8737     PetscScalar values[3] = {0.0, 0.0, 0.0};
8738 
8739     values[d] = 1.0;
8740     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8741     for (v = vStart; v < vEnd; ++v) {
8742       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8743     }
8744     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8745     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8746   }
8747   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8748   for (d = dim; d < dim*(dim+1)/2; ++d) {
8749     PetscInt i, j, k = dim > 2 ? d - dim : d;
8750 
8751     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8752     for (v = vStart; v < vEnd; ++v) {
8753       PetscScalar values[3] = {0.0, 0.0, 0.0};
8754       PetscInt    off;
8755 
8756       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8757       for (i = 0; i < dim; ++i) {
8758         for (j = 0; j < dim; ++j) {
8759           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
8760         }
8761       }
8762       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8763     }
8764     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8765     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8766   }
8767   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8768   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
8769   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
8770   /* Orthonormalize system */
8771   for (i = dim; i < m; ++i) {
8772     PetscScalar dots[6];
8773 
8774     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
8775     for (j = 0; j < i; ++j) dots[j] *= -1.0;
8776     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
8777     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
8778   }
8779   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
8780   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
8781   PetscFunctionReturn(0);
8782 }
8783 
8784 #undef __FUNCT__
8785 #define __FUNCT__ "DMPlexGetVTKBounds"
8786 PetscErrorCode DMPlexGetVTKBounds(DM dm, PetscInt *cMax, PetscInt *vMax)
8787 {
8788   DM_Plex *mesh = (DM_Plex *) dm->data;
8789 
8790   PetscFunctionBegin;
8791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8792   if (cMax) *cMax = mesh->vtkCellMax;
8793   if (vMax) *vMax = mesh->vtkVertexMax;
8794   PetscFunctionReturn(0);
8795 }
8796 
8797 #undef __FUNCT__
8798 #define __FUNCT__ "DMPlexSetVTKBounds"
8799 PetscErrorCode DMPlexSetVTKBounds(DM dm, PetscInt cMax, PetscInt vMax)
8800 {
8801   DM_Plex *mesh = (DM_Plex *) dm->data;
8802 
8803   PetscFunctionBegin;
8804   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8805   if (cMax >= 0) mesh->vtkCellMax   = cMax;
8806   if (vMax >= 0) mesh->vtkVertexMax = vMax;
8807   PetscFunctionReturn(0);
8808 }
8809 
8810 #undef __FUNCT__
8811 #define __FUNCT__ "DMPlexGetVTKCellHeight"
8812 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8813 {
8814   DM_Plex *mesh = (DM_Plex *) dm->data;
8815 
8816   PetscFunctionBegin;
8817   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8818   PetscValidPointer(cellHeight, 2);
8819   *cellHeight = mesh->vtkCellHeight;
8820   PetscFunctionReturn(0);
8821 }
8822 
8823 #undef __FUNCT__
8824 #define __FUNCT__ "DMPlexSetVTKCellHeight"
8825 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8826 {
8827   DM_Plex *mesh = (DM_Plex *) dm->data;
8828 
8829   PetscFunctionBegin;
8830   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8831   mesh->vtkCellHeight = cellHeight;
8832   PetscFunctionReturn(0);
8833 }
8834 
8835 #undef __FUNCT__
8836 #define __FUNCT__ "DMPlexInsertFace_Private"
8837 /*
8838   DMPlexInsertFace_Private - Puts a face into the mesh
8839 
8840   Not collective
8841 
8842   Input Parameters:
8843   + dm              - The DMPlex
8844   . numFaceVertex   - The number of vertices in the face
8845   . faceVertices    - The vertices in the face for dm
8846   . subfaceVertices - The vertices in the face for subdm
8847   . numCorners      - The number of vertices in the cell
8848   . cell            - A cell in dm containing the face
8849   . subcell         - A cell in subdm containing the face
8850   . firstFace       - First face in the mesh
8851   - newFacePoint    - Next face in the mesh
8852 
8853   Output Parameters:
8854   . newFacePoint - Contains next face point number on input, updated on output
8855 
8856   Level: developer
8857 */
8858 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)
8859 {
8860   MPI_Comm        comm    = ((PetscObject) dm)->comm;
8861   DM_Plex     *submesh = (DM_Plex *) subdm->data;
8862   const PetscInt *faces;
8863   PetscInt        numFaces, coneSize;
8864   PetscErrorCode  ierr;
8865 
8866   PetscFunctionBegin;
8867   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
8868   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
8869 #if 0
8870   /* Cannot use this because support() has not been constructed yet */
8871   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
8872 #else
8873   {
8874     PetscInt f;
8875 
8876     numFaces = 0;
8877     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
8878     for(f = firstFace; f < *newFacePoint; ++f) {
8879       PetscInt dof, off, d;
8880 
8881       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
8882       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
8883       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
8884       for(d = 0; d < dof; ++d) {
8885         const PetscInt p = submesh->cones[off+d];
8886         PetscInt       v;
8887 
8888         for(v = 0; v < numFaceVertices; ++v) {
8889           if (subfaceVertices[v] == p) break;
8890         }
8891         if (v == numFaceVertices) break;
8892       }
8893       if (d == dof) {
8894         numFaces = 1;
8895         ((PetscInt *) faces)[0] = f;
8896       }
8897     }
8898   }
8899 #endif
8900   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
8901   else if (numFaces == 1) {
8902     /* Add the other cell neighbor for this face */
8903     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
8904   } else {
8905     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
8906     PetscBool posOriented;
8907 
8908     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
8909     origVertices = &orientedVertices[numFaceVertices];
8910     indices      = &orientedVertices[numFaceVertices*2];
8911     orientedSubVertices = &orientedVertices[numFaceVertices*3];
8912     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
8913     /* TODO: I know that routine should return a permutation, not the indices */
8914     for(v = 0; v < numFaceVertices; ++v) {
8915       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
8916       for(ov = 0; ov < numFaceVertices; ++ov) {
8917         if (orientedVertices[ov] == vertex) {
8918           orientedSubVertices[ov] = subvertex;
8919           break;
8920         }
8921       }
8922       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
8923     }
8924     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
8925     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
8926     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
8927     ++(*newFacePoint);
8928   }
8929   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
8930   PetscFunctionReturn(0);
8931 }
8932 
8933 #undef __FUNCT__
8934 #define __FUNCT__ "DMPlexCreateSubmesh"
8935 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
8936 {
8937   MPI_Comm        comm = ((PetscObject) dm)->comm;
8938   DM_Plex     *submesh;
8939   PetscBool       boundaryFaces = PETSC_FALSE;
8940   PetscSection    coordSection, subCoordSection;
8941   Vec             coordinates, subCoordinates;
8942   PetscScalar    *coords, *subCoords;
8943   IS              labelIS;
8944   const PetscInt *subVertices;
8945   PetscInt       *subVerticesActive, *tmpPoints;
8946   PetscInt       *subCells = PETSC_NULL;
8947   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
8948   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
8949   PetscInt        dim; /* Right now, do not specify dimension */
8950   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
8951   PetscErrorCode  ierr;
8952 
8953   PetscFunctionBegin;
8954   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8955   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8956   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8957   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
8958   ierr = DMPlexGetVTKBounds(dm, &cMax, &vMax);CHKERRQ(ierr);
8959   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8960   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
8961   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
8962   subface = &face[maxConeSize];
8963   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
8964   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
8965   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
8966   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
8967   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
8968   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
8969   maxSubCells = numSubVertices;
8970   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
8971   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
8972   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
8973   for(v = 0; v < numSubVertices; ++v) {
8974     const PetscInt vertex = subVertices[v];
8975     PetscInt *star = PETSC_NULL;
8976     PetscInt  starSize, numCells = 0;
8977 
8978     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
8979     for(p = 0; p < starSize*2; p += 2) {
8980       const PetscInt point = star[p];
8981       if ((point >= cStart) && (point < cEnd)) {
8982         star[numCells++] = point;
8983       }
8984     }
8985     numOldSubCells = numSubCells;
8986     for(c = 0; c < numCells; ++c) {
8987       const PetscInt cell    = star[c];
8988       PetscInt      *closure = PETSC_NULL;
8989       PetscInt       closureSize, numCorners = 0, faceSize = 0;
8990       PetscInt       cellLoc;
8991 
8992       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
8993       if (cellLoc >= 0) continue;
8994       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8995       for(p = 0; p < closureSize*2; p += 2) {
8996         const PetscInt point = closure[p];
8997         if ((point >= vStart) && (point < vEnd)) {
8998           closure[numCorners++] = point;
8999         }
9000       }
9001       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9002       for(corner = 0; corner < numCorners; ++corner) {
9003         const PetscInt cellVertex = closure[corner];
9004         PetscInt       subVertex;
9005 
9006         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
9007         if (subVertex >= 0) { /* contains submesh vertex */
9008           for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9009           if (i == faceSize) {
9010             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
9011             face[faceSize]    = cellVertex;
9012             subface[faceSize] = subVertex;
9013             ++faceSize;
9014           }
9015         }
9016       }
9017       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9018       if (faceSize >= nFV) {
9019         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9020         if (numSubCells >= maxSubCells) {
9021           PetscInt *tmpCells;
9022           maxSubCells *= 2;
9023           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
9024           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
9025           ierr = PetscFree(subCells);CHKERRQ(ierr);
9026           subCells = tmpCells;
9027         }
9028         /* TOOD: Maybe overestimate then squeeze out empty faces */
9029         if (faceSize > nFV) {
9030           /* TODO: This is tricky. Maybe just add all faces */
9031           numSubFaces++;
9032         } else {
9033           numSubFaces++;
9034         }
9035         for(f = 0; f < faceSize; ++f) {
9036           subVerticesActive[subface[f]] = 1;
9037         }
9038         subCells[numSubCells++] = cell;
9039       }
9040     }
9041     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9042     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
9043   }
9044   /* Pick out active subvertices */
9045   for(v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
9046     if (subVerticesActive[v]) {
9047       subVerticesActive[numSubVerticesActive++] = subVertices[v];
9048     }
9049   }
9050   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
9051   /* Set cone sizes */
9052   firstSubVertex = numSubCells;
9053   firstSubFace   = numSubCells+numSubVerticesActive;
9054   newFacePoint   = firstSubFace;
9055   for(c = 0; c < numSubCells; ++c) {
9056     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
9057   }
9058   for(f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
9059     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
9060   }
9061   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
9062   /* Create face cones */
9063   for(c = 0; c < numSubCells; ++c) {
9064     const PetscInt cell    = subCells[c];
9065     PetscInt      *closure = PETSC_NULL;
9066     PetscInt       closureSize, numCorners = 0, faceSize = 0;
9067 
9068     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9069     for(p = 0; p < closureSize*2; p += 2) {
9070       const PetscInt point = closure[p];
9071       if ((point >= vStart) && (point < vEnd)) {
9072         closure[numCorners++] = point;
9073       }
9074     }
9075     for(corner = 0; corner < numCorners; ++corner) {
9076       const PetscInt cellVertex = closure[corner];
9077       PetscInt       subVertex;
9078 
9079       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
9080       if (subVertex >= 0) { /* contains submesh vertex */
9081         for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9082         if (i == faceSize) {
9083           face[faceSize]    = cellVertex;
9084           subface[faceSize] = numSubCells+subVertex;
9085           ++faceSize;
9086         }
9087       }
9088     }
9089     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9090     if (faceSize >= nFV) {
9091       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9092       // Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron)
9093       //   We have to take all the faces, and discard those in the interior
9094       //   We check the join of the face vertices, which produces 2 cells if in the interior
9095 #if 0
9096       // This object just calls insert on each face that comes from subsets()
9097       // In fact, we can just always acll subsets(), since when we pass a single face it is a single call
9098       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
9099       PointArray                          faceVec(face->begin(), face->end());
9100 
9101       subsets(faceVec, nFV, inserter);
9102 #endif
9103       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
9104     }
9105   }
9106   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
9107   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
9108   /* Build coordinates */
9109   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9110   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9111   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
9112   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
9113   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
9114     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
9115   }
9116   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
9117   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
9118   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
9119   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
9120   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
9121   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
9122   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9123   for(v = 0; v < numSubVerticesActive; ++v) {
9124     const PetscInt vertex    = subVerticesActive[v];
9125     const PetscInt subVertex = firstSubVertex+v;
9126     PetscInt dof, off, sdof, soff;
9127 
9128     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
9129     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
9130     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
9131     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
9132     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
9133     for(d = 0; d < dof; ++d) {
9134       subCoords[soff+d] = coords[off+d];
9135     }
9136   }
9137   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
9138   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9139   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
9140   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
9141 
9142   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
9143   /* Create map from submesh points to original mesh points */
9144   submesh = (DM_Plex *) (*subdm)->data;
9145   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
9146   for(c = 0; c < numSubCells; ++c) {
9147     tmpPoints[c] = subCells[c];
9148   }
9149   for(v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
9150     tmpPoints[v] = subVerticesActive[v-numSubCells];
9151   }
9152   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
9153 
9154   ierr = PetscFree(subCells);CHKERRQ(ierr);
9155   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
9156   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
9157   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
9158   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9159   PetscFunctionReturn(0);
9160 }
9161 
9162 #undef __FUNCT__
9163 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9164 /* We can easily have a form that takes an IS instead */
9165 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9166 {
9167   PetscSection   section, globalSection;
9168   PetscInt      *numbers, p;
9169   PetscErrorCode ierr;
9170 
9171   PetscFunctionBegin;
9172   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
9173   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9174   for(p = pStart; p < pEnd; ++p) {
9175     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9176   }
9177   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9178   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9179   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9180   for(p = pStart; p < pEnd; ++p) {
9181     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9182   }
9183   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9184   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9185   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9186   PetscFunctionReturn(0);
9187 }
9188 
9189 #undef __FUNCT__
9190 #define __FUNCT__ "DMPlexGetCellNumbering"
9191 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9192 {
9193   DM_Plex    *mesh = (DM_Plex *) dm->data;
9194   PetscInt       cellHeight, cStart, cEnd, cMax;
9195   PetscErrorCode ierr;
9196 
9197   PetscFunctionBegin;
9198   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9199   if (!mesh->globalCellNumbers) {
9200     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9201     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9202     ierr = DMPlexGetVTKBounds(dm, &cMax, PETSC_NULL);CHKERRQ(ierr);
9203     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9204     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9205   }
9206   *globalCellNumbers = mesh->globalCellNumbers;
9207   PetscFunctionReturn(0);
9208 }
9209 
9210 #undef __FUNCT__
9211 #define __FUNCT__ "DMPlexGetVertexNumbering"
9212 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9213 {
9214   DM_Plex    *mesh = (DM_Plex *) dm->data;
9215   PetscInt       vStart, vEnd, vMax;
9216   PetscErrorCode ierr;
9217 
9218   PetscFunctionBegin;
9219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9220   if (!mesh->globalVertexNumbers) {
9221     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9222     ierr = DMPlexGetVTKBounds(dm, PETSC_NULL, &vMax);CHKERRQ(ierr);
9223     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9224     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9225   }
9226   *globalVertexNumbers = mesh->globalVertexNumbers;
9227   PetscFunctionReturn(0);
9228 }
9229 
9230 #undef __FUNCT__
9231 #define __FUNCT__ "DMPlexGetSubpointMap"
9232 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
9233 {
9234   DM_Plex *mesh = (DM_Plex *) dm->data;
9235 
9236   PetscFunctionBegin;
9237   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9238   PetscValidPointer(subpointMap, 2);
9239   *subpointMap = mesh->subpointMap;
9240   PetscFunctionReturn(0);
9241 }
9242 
9243 #undef __FUNCT__
9244 #define __FUNCT__ "DMPlexSetSubpointMap"
9245 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
9246 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
9247 {
9248   DM_Plex *mesh = (DM_Plex *) dm->data;
9249 
9250   PetscFunctionBegin;
9251   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9252   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
9253   mesh->subpointMap = subpointMap;
9254   PetscFunctionReturn(0);
9255 }
9256 
9257 #undef __FUNCT__
9258 #define __FUNCT__ "DMPlexGetScale"
9259 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9260 {
9261   DM_Plex *mesh = (DM_Plex *) dm->data;
9262 
9263   PetscFunctionBegin;
9264   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9265   PetscValidPointer(scale, 3);
9266   *scale = mesh->scale[unit];
9267   PetscFunctionReturn(0);
9268 }
9269 
9270 #undef __FUNCT__
9271 #define __FUNCT__ "DMPlexSetScale"
9272 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9273 {
9274   DM_Plex *mesh = (DM_Plex *) dm->data;
9275 
9276   PetscFunctionBegin;
9277   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9278   mesh->scale[unit] = scale;
9279   PetscFunctionReturn(0);
9280 }
9281 
9282 
9283 /*******************************************************************************
9284 This should be in a separate Discretization object, but I am not sure how to lay
9285 it out yet, so I am stuffing things here while I experiment.
9286 *******************************************************************************/
9287 #undef __FUNCT__
9288 #define __FUNCT__ "DMPlexSetFEMIntegration"
9289 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9290                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9291                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9292                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9293                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9294                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9295                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9296                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9297                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9298                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9299                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9300                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9301                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9302                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9303                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9304                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9305                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9306 {
9307   DM_Plex *mesh = (DM_Plex *) dm->data;
9308 
9309   PetscFunctionBegin;
9310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9311   mesh->integrateResidualFEM       = integrateResidualFEM;
9312   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9313   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9314   PetscFunctionReturn(0);
9315 }
9316 
9317 #undef __FUNCT__
9318 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9319 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9320 {
9321   Vec            coordinates;
9322   PetscSection   section, cSection;
9323   PetscInt       dim, vStart, vEnd, v, c, d;
9324   PetscScalar   *values, *cArray;
9325   PetscReal     *coords;
9326   PetscErrorCode ierr;
9327 
9328   PetscFunctionBegin;
9329   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9330   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9331   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9332   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9333   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9334   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9335   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9336   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9337   for (v = vStart; v < vEnd; ++v) {
9338     PetscInt dof, off;
9339 
9340     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9341     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9342     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9343     for(d = 0; d < dof; ++d) {
9344       coords[d] = PetscRealPart(cArray[off+d]);
9345     }
9346     for(c = 0; c < numComp; ++c) {
9347       values[c] = (*funcs[c])(coords);
9348     }
9349     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9350   }
9351   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9352   /* Temporary, must be replaced by a projection on the finite element basis */
9353   {
9354     PetscInt eStart = 0, eEnd = 0, e, depth;
9355 
9356     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9357     --depth;
9358     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9359     for (e = eStart; e < eEnd; ++e) {
9360       const PetscInt *cone = PETSC_NULL;
9361       PetscInt        coneSize, d;
9362       PetscScalar    *coordsA, *coordsB;
9363 
9364       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9365       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9366       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9367       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9368       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9369       for (d = 0; d < dim; ++d) {
9370         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9371       }
9372       for (c = 0; c < numComp; ++c) {
9373         values[c] = (*funcs[c])(coords);
9374       }
9375       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9376     }
9377   }
9378 
9379   ierr = PetscFree(coords);CHKERRQ(ierr);
9380   ierr = PetscFree(values);CHKERRQ(ierr);
9381 #if 0
9382   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9383   PetscReal      detJ;
9384 
9385   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9386   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9387   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV((int) pow(this->_mesh->getSieve()->getMaxConeSize(), dim+1)+1, true);
9388 
9389   for (PetscInt c = cStart; c < cEnd; ++c) {
9390     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9391     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9392     const int                          oSize   = pV.getSize();
9393     int                                v       = 0;
9394 
9395     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
9396     for (PetscInt cl = 0; cl < oSize; ++cl) {
9397       const PetscInt fDim;
9398 
9399       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9400       if (pointDim) {
9401         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9402           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9403         }
9404       }
9405     }
9406     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
9407     pV.clear();
9408   }
9409   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9410   ierr = PetscFree(values);CHKERRQ(ierr);
9411 #endif
9412   PetscFunctionReturn(0);
9413 }
9414 
9415 #undef __FUNCT__
9416 #define __FUNCT__ "DMPlexProjectFunction"
9417 /*@C
9418   DMPlexProjectFunction - This projects the given function into the function space provided.
9419 
9420   Input Parameters:
9421 + dm      - The DM
9422 . numComp - The number of components (functions)
9423 . funcs   - The coordinate functions to evaluate
9424 - mode    - The insertion mode for values
9425 
9426   Output Parameter:
9427 . X - vector
9428 
9429   Level: developer
9430 
9431   Note:
9432   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9433   We will eventually fix it.
9434 
9435 ,seealso: DMPlexComputeL2Diff()
9436 */
9437 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9438 {
9439   Vec            localX;
9440   PetscErrorCode ierr;
9441 
9442   PetscFunctionBegin;
9443   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9444   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9445   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9446   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9447   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9448   PetscFunctionReturn(0);
9449 }
9450 
9451 #undef __FUNCT__
9452 #define __FUNCT__ "DMPlexComputeL2Diff"
9453 /*@C
9454   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9455 
9456   Input Parameters:
9457 + dm    - The DM
9458 . quad  - The PetscQuadrature object for each field
9459 . funcs - The functions to evaluate for each field component
9460 - X     - The coefficient vector u_h
9461 
9462   Output Parameter:
9463 . diff - The diff ||u - u_h||_2
9464 
9465   Level: developer
9466 
9467 .seealso: DMPlexProjectFunction()
9468 */
9469 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff) {
9470   const PetscInt   debug = 0;
9471   PetscSection     section;
9472   Vec              localX;
9473   PetscReal       *coords, *v0, *J, *invJ, detJ;
9474   PetscReal        localDiff = 0.0;
9475   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9476   PetscErrorCode   ierr;
9477 
9478   PetscFunctionBegin;
9479   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9480   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9481   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9482   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9483   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9484   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9485   for (field = 0; field < numFields; ++field) {
9486     numComponents += quad[field].numComponents;
9487   }
9488   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9489   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9490   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9491   for (c = cStart; c < cEnd; ++c) {
9492     const PetscScalar *x;
9493     PetscReal          elemDiff = 0.0;
9494 
9495     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9496     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9497     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
9498 
9499     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9500       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9501       const PetscReal *quadPoints    = quad[field].quadPoints;
9502       const PetscReal *quadWeights   = quad[field].quadWeights;
9503       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9504       const PetscInt   numBasisComps = quad[field].numComponents;
9505       const PetscReal *basis         = quad[field].basis;
9506       PetscInt         q, d, e, fc, f;
9507 
9508       if (debug) {
9509         char title[1024];
9510         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9511         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9512       }
9513       for (q = 0; q < numQuadPoints; ++q) {
9514         for (d = 0; d < dim; d++) {
9515           coords[d] = v0[d];
9516           for (e = 0; e < dim; e++) {
9517             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9518           }
9519         }
9520         for (fc = 0; fc < numBasisComps; ++fc) {
9521           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9522           PetscReal       interpolant = 0.0;
9523           for (f = 0; f < numBasisFuncs; ++f) {
9524             const PetscInt fidx = f*numBasisComps+fc;
9525             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9526           }
9527           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9528           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9529         }
9530       }
9531       comp        += numBasisComps;
9532       fieldOffset += numBasisFuncs*numBasisComps;
9533     }
9534     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
9535     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9536     localDiff += elemDiff;
9537   }
9538   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9539   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9540   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9541   *diff = PetscSqrtReal(*diff);
9542   PetscFunctionReturn(0);
9543 }
9544 
9545 #undef __FUNCT__
9546 #define __FUNCT__ "DMPlexComputeResidualFEM"
9547 /*@
9548   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9549 
9550   Input Parameters:
9551 + dm - The mesh
9552 . X  - Local input vector
9553 - user - The user context
9554 
9555   Output Parameter:
9556 . F  - Local output vector
9557 
9558   Note:
9559   The second member of the user context must be an FEMContext.
9560 
9561   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9562   like a GPU, or vectorize on a multicore machine.
9563 
9564 .seealso: DMPlexComputeJacobianActionFEM()
9565 */
9566 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9567 {
9568   DM_Plex      *mesh = (DM_Plex *) dm->data;
9569   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9570   PetscQuadrature *quad = fem->quad;
9571   PetscSection     section;
9572   PetscReal       *v0, *J, *invJ, *detJ;
9573   PetscScalar     *elemVec, *u;
9574   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9575   PetscInt         cellDof = 0, numComponents = 0;
9576   PetscErrorCode   ierr;
9577 
9578   PetscFunctionBegin;
9579   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9580   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9581   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9582   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9583   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9584   numCells = cEnd - cStart;
9585   for (field = 0; field < numFields; ++field) {
9586     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9587     numComponents += quad[field].numComponents;
9588   }
9589   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9590   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9591   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);
9592   for (c = cStart; c < cEnd; ++c) {
9593     const PetscScalar *x;
9594     PetscInt           i;
9595 
9596     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9597     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9598     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9599 
9600     for (i = 0; i < cellDof; ++i) {
9601       u[c*cellDof+i] = x[i];
9602     }
9603     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9604   }
9605   for (field = 0; field < numFields; ++field) {
9606     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9607     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9608     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9609     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9610     /* Conforming batches */
9611     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9612     PetscInt numBlocks  = 1;
9613     PetscInt batchSize  = numBlocks * blockSize;
9614     PetscInt numBatches = numBatchesTmp;
9615     PetscInt numChunks  = numCells / (numBatches*batchSize);
9616     /* Remainder */
9617     PetscInt numRemainder = numCells % (numBatches * batchSize);
9618     PetscInt offset       = numCells - numRemainder;
9619 
9620     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9621     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9622                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9623   }
9624   for (c = cStart; c < cEnd; ++c) {
9625     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9626     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9627   }
9628   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9629   if (mesh->printFEM) {
9630     PetscMPIInt rank, numProcs;
9631     PetscInt    p;
9632 
9633     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9634     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9635     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9636     for (p = 0; p < numProcs; ++p) {
9637       if (p == rank) {
9638         Vec f;
9639 
9640         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9641         ierr = VecCopy(F, f);CHKERRQ(ierr);
9642         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9643         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9644         ierr = VecDestroy(&f);CHKERRQ(ierr);
9645         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9646       }
9647       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9648     }
9649   }
9650   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9651   PetscFunctionReturn(0);
9652 }
9653 
9654 #undef __FUNCT__
9655 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9656 /*@C
9657   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9658 
9659   Input Parameters:
9660 + dm - The mesh
9661 . J  - The Jacobian shell matrix
9662 . X  - Local input vector
9663 - user - The user context
9664 
9665   Output Parameter:
9666 . F  - Local output vector
9667 
9668   Note:
9669   The second member of the user context must be an FEMContext.
9670 
9671   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9672   like a GPU, or vectorize on a multicore machine.
9673 
9674 .seealso: DMPlexComputeResidualFEM()
9675 */
9676 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9677 {
9678   DM_Plex      *mesh = (DM_Plex *) dm->data;
9679   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9680   PetscQuadrature *quad = fem->quad;
9681   PetscSection     section;
9682   JacActionCtx    *jctx;
9683   PetscReal       *v0, *J, *invJ, *detJ;
9684   PetscScalar     *elemVec, *u, *a;
9685   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9686   PetscInt         cellDof = 0;
9687   PetscErrorCode   ierr;
9688 
9689   PetscFunctionBegin;
9690   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9691   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9692   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9693   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9694   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9695   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9696   numCells = cEnd - cStart;
9697   for (field = 0; field < numFields; ++field) {
9698     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9699   }
9700   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9701   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);
9702   for (c = cStart; c < cEnd; ++c) {
9703     const PetscScalar *x;
9704     PetscInt           i;
9705 
9706     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9707     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9708     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
9709     for (i = 0; i < cellDof; ++i) {
9710       u[c*cellDof+i] = x[i];
9711     }
9712     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
9713     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9714     for (i = 0; i < cellDof; ++i) {
9715       a[c*cellDof+i] = x[i];
9716     }
9717     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9718   }
9719   for (field = 0; field < numFields; ++field) {
9720     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9721     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9722     /* Conforming batches */
9723     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9724     PetscInt numBlocks  = 1;
9725     PetscInt batchSize  = numBlocks * blockSize;
9726     PetscInt numBatches = numBatchesTmp;
9727     PetscInt numChunks  = numCells / (numBatches*batchSize);
9728     /* Remainder */
9729     PetscInt numRemainder = numCells % (numBatches * batchSize);
9730     PetscInt offset       = numCells - numRemainder;
9731 
9732     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);
9733     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],
9734                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9735   }
9736   for (c = cStart; c < cEnd; ++c) {
9737     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9738     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9739   }
9740   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9741   if (mesh->printFEM) {
9742     PetscMPIInt rank, numProcs;
9743     PetscInt    p;
9744 
9745     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9746     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9747     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9748     for (p = 0; p < numProcs; ++p) {
9749       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9750       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9751     }
9752   }
9753   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9754   PetscFunctionReturn(0);
9755 }
9756 
9757 #undef __FUNCT__
9758 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9759 /*@
9760   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9761 
9762   Input Parameters:
9763 + dm - The mesh
9764 . X  - Local input vector
9765 - user - The user context
9766 
9767   Output Parameter:
9768 . Jac  - Jacobian matrix
9769 
9770   Note:
9771   The second member of the user context must be an FEMContext.
9772 
9773   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9774   like a GPU, or vectorize on a multicore machine.
9775 
9776 .seealso: FormFunctionLocal()
9777 */
9778 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9779 {
9780   DM_Plex      *mesh = (DM_Plex *) dm->data;
9781   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9782   PetscQuadrature *quad = fem->quad;
9783   PetscSection     section;
9784   PetscReal       *v0, *J, *invJ, *detJ;
9785   PetscScalar     *elemMat, *u;
9786   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9787   PetscInt         cellDof = 0, numComponents = 0;
9788   PetscBool        isShell;
9789   PetscErrorCode   ierr;
9790 
9791   PetscFunctionBegin;
9792   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9793   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9794   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9795   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9796   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9797   numCells = cEnd - cStart;
9798   for (field = 0; field < numFields; ++field) {
9799     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9800     numComponents += quad[field].numComponents;
9801   }
9802   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9803   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9804   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);
9805   for (c = cStart; c < cEnd; ++c) {
9806     const PetscScalar *x;
9807     PetscInt           i;
9808 
9809     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9810     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9811     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9812 
9813     for (i = 0; i < cellDof; ++i) {
9814       u[c*cellDof+i] = x[i];
9815     }
9816     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9817   }
9818   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9819   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9820     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9821     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9822     PetscInt       fieldJ;
9823 
9824     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9825       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9826       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9827       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9828       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9829       /* Conforming batches */
9830       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9831       PetscInt numBlocks  = 1;
9832       PetscInt batchSize  = numBlocks * blockSize;
9833       PetscInt numBatches = numBatchesTmp;
9834       PetscInt numChunks  = numCells / (numBatches*batchSize);
9835       /* Remainder */
9836       PetscInt numRemainder = numCells % (numBatches * batchSize);
9837       PetscInt offset       = numCells - numRemainder;
9838 
9839       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9840       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9841                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9842     }
9843   }
9844   for (c = cStart; c < cEnd; ++c) {
9845     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9846     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9847   }
9848   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9849 
9850   /* Assemble matrix, using the 2-step process:
9851        MatAssemblyBegin(), MatAssemblyEnd(). */
9852   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9853   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9854 
9855   if (mesh->printFEM) {
9856     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9857     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9858     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9859   }
9860   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9861   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9862   if (isShell) {
9863     JacActionCtx *jctx;
9864 
9865     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9866     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9867   }
9868   *str = SAME_NONZERO_PATTERN;
9869   PetscFunctionReturn(0);
9870 }
9871 
9872 
9873 #undef __FUNCT__
9874 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9875 /*@C
9876   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9877   the local section and an SF describing the section point overlap.
9878 
9879   Input Parameters:
9880   + s - The PetscSection for the local field layout
9881   . sf - The SF describing parallel layout of the section points
9882   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9883   . label - The label specifying the points
9884   - labelValue - The label stratum specifying the points
9885 
9886   Output Parameter:
9887   . gsection - The PetscSection for the global field layout
9888 
9889   Note: This gives negative sizes and offsets to points not owned by this process
9890 
9891   Level: developer
9892 
9893 .seealso: PetscSectionCreate()
9894 @*/
9895 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9896 {
9897   PetscInt      *neg;
9898   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9899   PetscErrorCode ierr;
9900 
9901   PetscFunctionBegin;
9902   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9903   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9904   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9905   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9906   /* Mark ghost points with negative dof */
9907   for (p = pStart; p < pEnd; ++p) {
9908     PetscInt value;
9909 
9910     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9911     if (value != labelValue) continue;
9912     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9913     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9914     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9915     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9916     neg[p-pStart] = -(dof+1);
9917   }
9918   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9919   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
9920   if (nroots >= 0) {
9921     if (nroots > pEnd - pStart) {
9922       PetscInt *tmpDof;
9923       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9924       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9925       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9926       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9927       for (p = pStart; p < pEnd; ++p) {
9928         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
9929       }
9930       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9931     } else {
9932       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9933       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9934     }
9935   }
9936   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9937   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9938     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9939     (*gsection)->atlasOff[p] = off;
9940     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9941   }
9942   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9943   globalOff -= off;
9944   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9945     (*gsection)->atlasOff[p] += globalOff;
9946     neg[p] = -((*gsection)->atlasOff[p]+1);
9947   }
9948   /* Put in negative offsets for ghost points */
9949   if (nroots >= 0) {
9950     if (nroots > pEnd - pStart) {
9951       PetscInt *tmpOff;
9952       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9953       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9954       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9955       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9956       for (p = pStart; p < pEnd; ++p) {
9957         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
9958       }
9959       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9960     } else {
9961       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9962       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9963     }
9964   }
9965   ierr = PetscFree(neg);CHKERRQ(ierr);
9966   PetscFunctionReturn(0);
9967 }
9968