xref: /petsc/src/dm/impls/plex/plex.c (revision a6dfd86ebdf75fa024070af26d51b62fd16650a3)
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, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for(p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for(v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for(e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for(c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = 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, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm = ((PetscObject) dm)->comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscMPIInt size;
282 
283     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
284     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
285     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
286     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
287     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
288     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
289     if (depth == 1) {
290       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
291       pEnd = pEnd - pStart;
292       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
293       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
294       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
295       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
296       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
297       pEnd = pEnd - pStart;
298       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
299       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
300       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
301       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
302     } else {
303       for (d = 0; d <= dim; d++) {
304         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
305         pEnd = pEnd - pStart;
306         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
307         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
308         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
309         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
310       }
311     }
312     ierr = PetscFree(sizes);CHKERRQ(ierr);
313   }
314   PetscFunctionReturn(0);
315 }
316 
317 #undef __FUNCT__
318 #define __FUNCT__ "DMView_Plex"
319 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
320 {
321   PetscBool      iascii, isbinary;
322   PetscErrorCode ierr;
323 
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
326   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
327   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
329   if (iascii) {
330     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
331 #if 0
332   } else if (isbinary) {
333     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
334 #endif
335   } else SETERRQ1(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"Viewer type %s not supported by this mesh object", ((PetscObject)viewer)->type_name);
336   PetscFunctionReturn(0);
337 }
338 
339 #undef __FUNCT__
340 #define __FUNCT__ "DMDestroy_Plex"
341 PetscErrorCode DMDestroy_Plex(DM dm)
342 {
343   DM_Plex    *mesh = (DM_Plex *) dm->data;
344   DMLabel        next = mesh->labels;
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   if (--mesh->refct > 0) {PetscFunctionReturn(0);}
349   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
350   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
352   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
353   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
355   while(next) {
356     DMLabel tmp = next->next;
357 
358     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
359     next = tmp;
360   }
361   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
362   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
364   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
365   ierr = PetscFree(mesh);CHKERRQ(ierr);
366   PetscFunctionReturn(0);
367 }
368 
369 #undef __FUNCT__
370 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
371 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
372 {
373   const PetscInt *support = PETSC_NULL;
374   PetscInt        numAdj  = 0, maxAdjSize = *adjSize, supportSize, s;
375   PetscErrorCode  ierr;
376 
377   PetscFunctionBegin;
378   if (useClosure) {
379     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
380     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
381     for (s = 0; s < supportSize; ++s) {
382       const PetscInt *cone = PETSC_NULL;
383       PetscInt        coneSize, c, q;
384 
385       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
386       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
387       for (c = 0; c < coneSize; ++c) {
388         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
389           if (cone[c] == adj[q]) break;
390         }
391         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
392       }
393     }
394   } else {
395     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
396     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
397     for (s = 0; s < supportSize; ++s) {
398       const PetscInt *cone = PETSC_NULL;
399       PetscInt        coneSize, c, q;
400 
401       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
402       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
403       for (c = 0; c < coneSize; ++c) {
404         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
405           if (cone[c] == adj[q]) break;
406         }
407         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
408       }
409     }
410   }
411   *adjSize = numAdj;
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "DMPlexGetAdjacency_Private"
417 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
418 {
419   const PetscInt *star   = tmpClosure;
420   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
421   PetscErrorCode  ierr;
422 
423   PetscFunctionBegin;
424   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt **) &star);CHKERRQ(ierr);
425   for (s = 2; s < starSize*2; s += 2) {
426     const PetscInt *closure = PETSC_NULL;
427     PetscInt        closureSize, c, q;
428 
429     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
430     for (c = 0; c < closureSize*2; c += 2) {
431       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
432         if (closure[c] == adj[q]) break;
433       }
434       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
435     }
436     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
437   }
438   *adjSize = numAdj;
439   PetscFunctionReturn(0);
440 }
441 
442 #undef __FUNCT__
443 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
444 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
445 {
446   DM_Plex *mesh = (DM_Plex *) dm->data;
447 
448   PetscFunctionBegin;
449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
450   mesh->preallocCenterDim = preallocCenterDim;
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "DMPlexPreallocateOperator"
456 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
457 {
458   DM_Plex        *mesh = (DM_Plex *) dm->data;
459   MPI_Comm           comm = ((PetscObject) dm)->comm;
460   PetscSF            sf, sfDof, sfAdj;
461   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
462   PetscInt           nleaves, l, p;
463   const PetscInt    *leaves;
464   const PetscSFNode *remotes;
465   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
466   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
467   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
468   PetscLayout        rLayout;
469   PetscInt           locRows, rStart, rEnd, r;
470   PetscMPIInt        size;
471   PetscBool          useClosure, debug = PETSC_FALSE;
472   PetscErrorCode     ierr;
473 
474   PetscFunctionBegin;
475   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
476   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
477   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
478   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
479   /* Create dof SF based on point SF */
480   if (debug) {
481     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
487   }
488   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
489   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
490   if (debug) {
491     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
492     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
493   }
494   /* Create section for dof adjacency (dof ==> # adj dof) */
495   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
496   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
497   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
498   if (mesh->preallocCenterDim == dim) {
499     useClosure = PETSC_FALSE;
500   } else if (mesh->preallocCenterDim == 0) {
501     useClosure = PETSC_TRUE;
502   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
503 
504   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
505   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
510   /*   Fill in the ghost dofs on the interface */
511   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
512   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
513   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
514   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
515   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
516   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
517 
518   /*
519    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
520     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
521        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
522     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
523        Create sfAdj connecting rootSectionAdj and leafSectionAdj
524     3. Visit unowned points on interface, write adjacencies to adj
525        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
526     4. Visit owned points on interface, write adjacencies to rootAdj
527        Remove redundancy in rootAdj
528    ** The last two traversals use transitive closure
529     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
530        Allocate memory addressed by sectionAdj (cols)
531     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
532    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
533   */
534 
535   for (l = 0; l < nleaves; ++l) {
536     PetscInt dof, off, d, q;
537     PetscInt p = leaves[l], numAdj = maxAdjSize;
538 
539     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
540     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
541     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
542     for (q = 0; q < numAdj; ++q) {
543       PetscInt ndof, ncdof;
544 
545       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
546       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
547       for (d = off; d < off+dof; ++d) {
548         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
549       }
550     }
551   }
552   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
553   if (debug) {
554     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
555     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
556   }
557   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
558   if (size > 1) {
559     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
560     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
561   }
562   if (debug) {
563     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
564     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
565   }
566   /* Add in local adjacency sizes for owned dofs on interface (roots) */
567   for (p = pStart; p < pEnd; ++p) {
568     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
569 
570     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
571     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
572     if (!dof) continue;
573     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
574     if (adof <= 0) continue;
575     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
576     for (q = 0; q < numAdj; ++q) {
577       PetscInt ndof, ncdof;
578 
579       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
580       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
581       for (d = off; d < off+dof; ++d) {
582         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
583       }
584     }
585   }
586   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
587   if (debug) {
588     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
589     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
590   }
591   /* Create adj SF based on dof SF */
592   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
593   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
596     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
597   }
598   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
599   /* Create leaf adjacency */
600   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
601   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
602   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
603   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
604   for (l = 0; l < nleaves; ++l) {
605     PetscInt dof, off, d, q;
606     PetscInt p = leaves[l], numAdj = maxAdjSize;
607 
608     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
609     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
610     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
611     for (d = off; d < off+dof; ++d) {
612       PetscInt aoff, i = 0;
613 
614       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
615       for (q = 0; q < numAdj; ++q) {
616         PetscInt  ndof, ncdof, ngoff, nd;
617 
618         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
619         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
620         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
621         for (nd = 0; nd < ndof-ncdof; ++nd) {
622           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
623           ++i;
624         }
625       }
626     }
627   }
628   /* Debugging */
629   if (debug) {
630     IS tmp;
631     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
632     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
633     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
634   }
635   /* Gather adjacenct indices to root */
636   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
637   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
638   for (r = 0; r < adjSize; ++r) {
639     rootAdj[r] = -1;
640   }
641   if (size > 1) {
642     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
643     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
644   }
645   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
646   ierr = PetscFree(adj);CHKERRQ(ierr);
647   /* Debugging */
648   if (debug) {
649     IS tmp;
650     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
651     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
652     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
653   }
654   /* Add in local adjacency indices for owned dofs on interface (roots) */
655   for (p = pStart; p < pEnd; ++p) {
656     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
657 
658     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
659     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
660     if (!dof) continue;
661     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
662     if (adof <= 0) continue;
663     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
664     for (d = off; d < off+dof; ++d) {
665       PetscInt adof, aoff, i;
666 
667       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
668       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
669       i    = adof-1;
670       for (q = 0; q < numAdj; ++q) {
671         PetscInt ndof, ncdof, ngoff, nd;
672 
673         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
674         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
675         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
676         for (nd = 0; nd < ndof-ncdof; ++nd) {
677           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
678           --i;
679         }
680       }
681     }
682   }
683   /* Debugging */
684   if (debug) {
685     IS tmp;
686     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
687     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
688     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
689   }
690   /* Compress indices */
691   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
692   for (p = pStart; p < pEnd; ++p) {
693     PetscInt dof, cdof, off, d;
694     PetscInt adof, aoff;
695 
696     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
697     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
698     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
699     if (!dof) continue;
700     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
701     if (adof <= 0) continue;
702     for (d = off; d < off+dof-cdof; ++d) {
703       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
704       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
705       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
706       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
707     }
708   }
709   /* Debugging */
710   if (debug) {
711     IS tmp;
712     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
713     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
714     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
715     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
716     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
717   }
718   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
719   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
720   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
721   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
722   for (p = pStart; p < pEnd; ++p) {
723     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
724     PetscBool found  = PETSC_TRUE;
725 
726     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
727     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
728     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
729     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
730     for (d = 0; d < dof-cdof; ++d) {
731       PetscInt ldof, rdof;
732 
733       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
734       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
735       if (ldof > 0) {
736         /* We do not own this point */
737       } else if (rdof > 0) {
738         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
739       } else {
740         found = PETSC_FALSE;
741       }
742     }
743     if (found) continue;
744     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
745     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
746     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
747     for (q = 0; q < numAdj; ++q) {
748       PetscInt ndof, ncdof, noff;
749 
750       /* Adjacent points may not be in the section chart */
751       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
752       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
753       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
754       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
755       for (d = goff; d < goff+dof-cdof; ++d) {
756         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
757       }
758     }
759   }
760   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
761   if (debug) {
762     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
763     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
764   }
765   /* Get adjacent indices */
766   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
767   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
768   for (p = pStart; p < pEnd; ++p) {
769     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
770     PetscBool found  = PETSC_TRUE;
771 
772     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
773     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
774     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
775     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
776     for (d = 0; d < dof-cdof; ++d) {
777       PetscInt ldof, rdof;
778 
779       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
780       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
781       if (ldof > 0) {
782         /* We do not own this point */
783       } else if (rdof > 0) {
784         PetscInt aoff, roff;
785 
786         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
787         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
788         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
789       } else {
790         found = PETSC_FALSE;
791       }
792     }
793     if (found) continue;
794     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
795     for (d = goff; d < goff+dof-cdof; ++d) {
796       PetscInt adof, aoff, i = 0;
797 
798       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
799       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
800       for (q = 0; q < numAdj; ++q) {
801         PetscInt        ndof, ncdof, ngoff, nd;
802         const PetscInt *ncind;
803 
804         /* Adjacent points may not be in the section chart */
805         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
806         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
807         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
808         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
809         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
810         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
811           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
812         }
813       }
814       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
815     }
816   }
817   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
818   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
819   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
820   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
821   /* Debugging */
822   if (debug) {
823     IS tmp;
824     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
825     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
826     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
827   }
828   /* Create allocation vectors from adjacency graph */
829   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
830   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
831   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
832   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
833   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
834   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
835   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
836   /* Only loop over blocks of rows */
837   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
838   for (r = rStart/bs; r < rEnd/bs; ++r) {
839     const PetscInt row = r*bs;
840     PetscInt numCols, cStart, c;
841 
842     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
843     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
844     for (c = cStart; c < cStart+numCols; ++c) {
845       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
846         ++dnz[r-rStart];
847         if (cols[c] >= row) {++dnzu[r-rStart];}
848       } else {
849         ++onz[r-rStart];
850         if (cols[c] >= row) {++onzu[r-rStart];}
851       }
852     }
853   }
854   if (bs > 1) {
855     for (r = 0; r < locRows/bs; ++r) {
856       dnz[r]  /= bs;
857       onz[r]  /= bs;
858       dnzu[r] /= bs;
859       onzu[r] /= bs;
860     }
861   }
862   /* Set matrix pattern */
863   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
864   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
865   /* Fill matrix with zeros */
866   if (fillMatrix) {
867     PetscScalar *values;
868     PetscInt     maxRowLen = 0;
869 
870     for (r = rStart; r < rEnd; ++r) {
871       PetscInt len;
872 
873       ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
874       maxRowLen = PetscMax(maxRowLen, len);
875     }
876     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
877     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
878     for (r = rStart; r < rEnd; ++r) {
879       PetscInt numCols, cStart;
880 
881       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
882       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
883       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
884     }
885     ierr = PetscFree(values);CHKERRQ(ierr);
886     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
887     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
888   }
889   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
890   ierr = PetscFree(cols);CHKERRQ(ierr);
891   PetscFunctionReturn(0);
892 }
893 
894 #if 0
895 #undef __FUNCT__
896 #define __FUNCT__ "DMPlexPreallocateOperator_2"
897 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
898 {
899   PetscErrorCode ierr;
900   PetscInt c,cStart,cEnd,pStart,pEnd;
901   PetscInt *tmpClosure,*tmpAdj,*visits;
902 
903   PetscFunctionBegin;
904   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
905   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
906   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
907   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
908   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
911   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
912   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
914   for (c=cStart; c<cEnd; c++) {
915     PetscInt *support = tmpClosure;
916     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
917     for (p=0; p<supportSize; p++) {
918       lvisits[support[p]]++;
919     }
920   }
921   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
923   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
925 
926   ierr = PetscSFGetRanks();CHKERRQ(ierr);
927 
928 
929   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
930   for (c=cStart; c<cEnd; c++) {
931     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
932     /*
933      Depth-first walk of transitive closure.
934      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.
935      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
936      */
937   }
938 
939   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
940   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
941   PetscFunctionReturn(0);
942 }
943 #endif
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "DMCreateMatrix_Plex"
947 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
948 {
949   PetscSection   section, sectionGlobal;
950   PetscInt       bs = -1;
951   PetscInt       localSize;
952   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
953   PetscErrorCode ierr;
954 
955   PetscFunctionBegin;
956 #ifndef PETSC_USE_DYNAMIC_LIBRARIES
957   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
958 #endif
959   if (!mtype) mtype = MATAIJ;
960   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
961   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
962   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
963   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
964   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
965   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
966   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
967   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
974   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
975   /* Check for symmetric storage */
976   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
977   if (isSymmetric) {
978     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
979   }
980   if (!isShell) {
981     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
982     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal;
983 
984     if (bs < 0) {
985       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
986         PetscInt pStart, pEnd, p, dof;
987 
988         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
989         for (p = pStart; p < pEnd; ++p) {
990           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
991           if (dof) {
992             bs = dof;
993             break;
994           }
995         }
996       } else {
997         bs = 1;
998       }
999       /* Must have same blocksize on all procs (some might have no points) */
1000       bsLocal = bs;
1001       ierr = MPI_Allreduce(&bsLocal, &bs, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1002     }
1003     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1004     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1005     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1006     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1007     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1008     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1009     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1010   }
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 #undef __FUNCT__
1015 #define __FUNCT__ "DMPlexGetDimension"
1016 /*@
1017   DMPlexGetDimension - Return the topological mesh dimension
1018 
1019   Not collective
1020 
1021   Input Parameter:
1022 . mesh - The DMPlex
1023 
1024   Output Parameter:
1025 . dim - The topological mesh dimension
1026 
1027   Level: beginner
1028 
1029 .seealso: DMPlexCreate()
1030 @*/
1031 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1032 {
1033   DM_Plex *mesh = (DM_Plex *) dm->data;
1034 
1035   PetscFunctionBegin;
1036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1037   PetscValidPointer(dim, 2);
1038   *dim = mesh->dim;
1039   PetscFunctionReturn(0);
1040 }
1041 
1042 #undef __FUNCT__
1043 #define __FUNCT__ "DMPlexSetDimension"
1044 /*@
1045   DMPlexSetDimension - Set the topological mesh dimension
1046 
1047   Collective on mesh
1048 
1049   Input Parameters:
1050 + mesh - The DMPlex
1051 - dim - The topological mesh dimension
1052 
1053   Level: beginner
1054 
1055 .seealso: DMPlexCreate()
1056 @*/
1057 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1058 {
1059   DM_Plex *mesh = (DM_Plex *) dm->data;
1060 
1061   PetscFunctionBegin;
1062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1063   PetscValidLogicalCollectiveInt(dm, dim, 2);
1064   mesh->dim = dim;
1065   mesh->preallocCenterDim = dim;
1066   PetscFunctionReturn(0);
1067 }
1068 
1069 #undef __FUNCT__
1070 #define __FUNCT__ "DMPlexGetChart"
1071 /*@
1072   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1073 
1074   Not collective
1075 
1076   Input Parameter:
1077 . mesh - The DMPlex
1078 
1079   Output Parameters:
1080 + pStart - The first mesh point
1081 - pEnd   - The upper bound for mesh points
1082 
1083   Level: beginner
1084 
1085 .seealso: DMPlexCreate(), DMPlexSetChart()
1086 @*/
1087 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1088 {
1089   DM_Plex    *mesh = (DM_Plex *) dm->data;
1090   PetscErrorCode ierr;
1091 
1092   PetscFunctionBegin;
1093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1094   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1095   PetscFunctionReturn(0);
1096 }
1097 
1098 #undef __FUNCT__
1099 #define __FUNCT__ "DMPlexSetChart"
1100 /*@
1101   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1102 
1103   Not collective
1104 
1105   Input Parameters:
1106 + mesh - The DMPlex
1107 . pStart - The first mesh point
1108 - pEnd   - The upper bound for mesh points
1109 
1110   Output Parameters:
1111 
1112   Level: beginner
1113 
1114 .seealso: DMPlexCreate(), DMPlexGetChart()
1115 @*/
1116 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1117 {
1118   DM_Plex    *mesh = (DM_Plex *) dm->data;
1119   PetscErrorCode ierr;
1120 
1121   PetscFunctionBegin;
1122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1123   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1124   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1125   PetscFunctionReturn(0);
1126 }
1127 
1128 #undef __FUNCT__
1129 #define __FUNCT__ "DMPlexGetConeSize"
1130 /*@
1131   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1132 
1133   Not collective
1134 
1135   Input Parameters:
1136 + mesh - The DMPlex
1137 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1138 
1139   Output Parameter:
1140 . size - The cone size for point p
1141 
1142   Level: beginner
1143 
1144 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1145 @*/
1146 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1147 {
1148   DM_Plex    *mesh = (DM_Plex *) dm->data;
1149   PetscErrorCode ierr;
1150 
1151   PetscFunctionBegin;
1152   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1153   PetscValidPointer(size, 3);
1154   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1155   PetscFunctionReturn(0);
1156 }
1157 
1158 #undef __FUNCT__
1159 #define __FUNCT__ "DMPlexSetConeSize"
1160 /*@
1161   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1162 
1163   Not collective
1164 
1165   Input Parameters:
1166 + mesh - The DMPlex
1167 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1168 - size - The cone size for point p
1169 
1170   Output Parameter:
1171 
1172   Note:
1173   This should be called after DMPlexSetChart().
1174 
1175   Level: beginner
1176 
1177 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1178 @*/
1179 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1180 {
1181   DM_Plex    *mesh = (DM_Plex *) dm->data;
1182   PetscErrorCode ierr;
1183 
1184   PetscFunctionBegin;
1185   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1186   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1187   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1188   PetscFunctionReturn(0);
1189 }
1190 
1191 #undef __FUNCT__
1192 #define __FUNCT__ "DMPlexGetCone"
1193 /*@C
1194   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1195 
1196   Not collective
1197 
1198   Input Parameters:
1199 + mesh - The DMPlex
1200 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1201 
1202   Output Parameter:
1203 . cone - An array of points which are on the in-edges for point p
1204 
1205   Level: beginner
1206 
1207   Note:
1208   This routine is not available in Fortran.
1209 
1210 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1211 @*/
1212 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1213 {
1214   DM_Plex    *mesh = (DM_Plex *) dm->data;
1215   PetscInt       off;
1216   PetscErrorCode ierr;
1217 
1218   PetscFunctionBegin;
1219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1220   PetscValidPointer(cone, 3);
1221   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1222   *cone = &mesh->cones[off];
1223   PetscFunctionReturn(0);
1224 }
1225 
1226 #undef __FUNCT__
1227 #define __FUNCT__ "DMPlexSetCone"
1228 /*@
1229   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1230 
1231   Not collective
1232 
1233   Input Parameters:
1234 + mesh - The DMPlex
1235 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1236 - cone - An array of points which are on the in-edges for point p
1237 
1238   Output Parameter:
1239 
1240   Note:
1241   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1242 
1243   Level: beginner
1244 
1245 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1246 @*/
1247 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1248 {
1249   DM_Plex    *mesh = (DM_Plex *) dm->data;
1250   PetscInt       pStart, pEnd;
1251   PetscInt       dof, off, c;
1252   PetscErrorCode ierr;
1253 
1254   PetscFunctionBegin;
1255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1256   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1257   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1258   if (dof) PetscValidPointer(cone, 3);
1259   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1260   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);
1261   for (c = 0; c < dof; ++c) {
1262     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);
1263     mesh->cones[off+c] = cone[c];
1264   }
1265   PetscFunctionReturn(0);
1266 }
1267 
1268 #undef __FUNCT__
1269 #define __FUNCT__ "DMPlexGetConeOrientation"
1270 /*@C
1271   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1272 
1273   Not collective
1274 
1275   Input Parameters:
1276 + mesh - The DMPlex
1277 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1278 
1279   Output Parameter:
1280 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1281                     integer giving the prescription for cone traversal. If it is negative, the cone is
1282                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1283                     the index of the cone point on which to start.
1284 
1285   Level: beginner
1286 
1287   Note:
1288   This routine is not available in Fortran.
1289 
1290 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1291 @*/
1292 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1293 {
1294   DM_Plex    *mesh = (DM_Plex *) dm->data;
1295   PetscInt       off;
1296   PetscErrorCode ierr;
1297 
1298   PetscFunctionBegin;
1299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1300 #if defined(PETSC_USE_DEBUG)
1301   {
1302     PetscInt dof;
1303     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1304     if (dof) PetscValidPointer(coneOrientation, 3);
1305   }
1306 #endif
1307   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1308   *coneOrientation = &mesh->coneOrientations[off];
1309   PetscFunctionReturn(0);
1310 }
1311 
1312 #undef __FUNCT__
1313 #define __FUNCT__ "DMPlexSetConeOrientation"
1314 /*@
1315   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1316 
1317   Not collective
1318 
1319   Input Parameters:
1320 + mesh - The DMPlex
1321 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1322 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1323                     integer giving the prescription for cone traversal. If it is negative, the cone is
1324                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1325                     the index of the cone point on which to start.
1326 
1327   Output Parameter:
1328 
1329   Note:
1330   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1331 
1332   Level: beginner
1333 
1334 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1335 @*/
1336 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1337 {
1338   DM_Plex    *mesh = (DM_Plex *) dm->data;
1339   PetscInt       pStart, pEnd;
1340   PetscInt       dof, off, c;
1341   PetscErrorCode ierr;
1342 
1343   PetscFunctionBegin;
1344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1345   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1346   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1347   if (dof) PetscValidPointer(coneOrientation, 3);
1348   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1349   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);
1350   for (c = 0; c < dof; ++c) {
1351     PetscInt cdof, o = coneOrientation[c];
1352 
1353     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1354     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);
1355     mesh->coneOrientations[off+c] = o;
1356   }
1357   PetscFunctionReturn(0);
1358 }
1359 
1360 #undef __FUNCT__
1361 #define __FUNCT__ "DMPlexInsertCone"
1362 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1363 {
1364   DM_Plex    *mesh = (DM_Plex *) dm->data;
1365   PetscInt       pStart, pEnd;
1366   PetscInt       dof, off;
1367   PetscErrorCode ierr;
1368 
1369   PetscFunctionBegin;
1370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1371   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1372   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1373   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1374   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);
1375   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);
1376   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);
1377   mesh->cones[off+conePos] = conePoint;
1378   PetscFunctionReturn(0);
1379 }
1380 
1381 #undef __FUNCT__
1382 #define __FUNCT__ "DMPlexGetSupportSize"
1383 /*@
1384   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1385 
1386   Not collective
1387 
1388   Input Parameters:
1389 + mesh - The DMPlex
1390 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1391 
1392   Output Parameter:
1393 . size - The support size for point p
1394 
1395   Level: beginner
1396 
1397 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1398 @*/
1399 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1400 {
1401   DM_Plex    *mesh = (DM_Plex *) dm->data;
1402   PetscErrorCode ierr;
1403 
1404   PetscFunctionBegin;
1405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1406   PetscValidPointer(size, 3);
1407   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1408   PetscFunctionReturn(0);
1409 }
1410 
1411 #undef __FUNCT__
1412 #define __FUNCT__ "DMPlexSetSupportSize"
1413 /*@
1414   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1415 
1416   Not collective
1417 
1418   Input Parameters:
1419 + mesh - The DMPlex
1420 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1421 - size - The support size for point p
1422 
1423   Output Parameter:
1424 
1425   Note:
1426   This should be called after DMPlexSetChart().
1427 
1428   Level: beginner
1429 
1430 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1431 @*/
1432 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1433 {
1434   DM_Plex    *mesh = (DM_Plex *) dm->data;
1435   PetscErrorCode ierr;
1436 
1437   PetscFunctionBegin;
1438   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1439   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1440   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1441   PetscFunctionReturn(0);
1442 }
1443 
1444 #undef __FUNCT__
1445 #define __FUNCT__ "DMPlexGetSupport"
1446 /*@C
1447   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1448 
1449   Not collective
1450 
1451   Input Parameters:
1452 + mesh - The DMPlex
1453 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1454 
1455   Output Parameter:
1456 . support - An array of points which are on the out-edges for point p
1457 
1458   Level: beginner
1459 
1460 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1461 @*/
1462 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1463 {
1464   DM_Plex    *mesh = (DM_Plex *) dm->data;
1465   PetscInt       off;
1466   PetscErrorCode ierr;
1467 
1468   PetscFunctionBegin;
1469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1470   PetscValidPointer(support, 3);
1471   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1472   *support = &mesh->supports[off];
1473   PetscFunctionReturn(0);
1474 }
1475 
1476 #undef __FUNCT__
1477 #define __FUNCT__ "DMPlexSetSupport"
1478 /*@
1479   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1480 
1481   Not collective
1482 
1483   Input Parameters:
1484 + mesh - The DMPlex
1485 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1486 - support - An array of points which are on the in-edges for point p
1487 
1488   Output Parameter:
1489 
1490   Note:
1491   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1492 
1493   Level: beginner
1494 
1495 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1496 @*/
1497 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1498 {
1499   DM_Plex    *mesh = (DM_Plex *) dm->data;
1500   PetscInt       pStart, pEnd;
1501   PetscInt       dof, off, c;
1502   PetscErrorCode ierr;
1503 
1504   PetscFunctionBegin;
1505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1506   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1507   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1508   if (dof) PetscValidPointer(support, 3);
1509   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1510   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);
1511   for (c = 0; c < dof; ++c) {
1512     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);
1513     mesh->supports[off+c] = support[c];
1514   }
1515   PetscFunctionReturn(0);
1516 }
1517 
1518 #undef __FUNCT__
1519 #define __FUNCT__ "DMPlexInsertSupport"
1520 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1521 {
1522   DM_Plex    *mesh = (DM_Plex *) dm->data;
1523   PetscInt       pStart, pEnd;
1524   PetscInt       dof, off;
1525   PetscErrorCode ierr;
1526 
1527   PetscFunctionBegin;
1528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1529   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1530   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1531   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1532   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);
1533   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);
1534   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);
1535   mesh->supports[off+supportPos] = supportPoint;
1536   PetscFunctionReturn(0);
1537 }
1538 
1539 #undef __FUNCT__
1540 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1541 /*@C
1542   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1543 
1544   Not collective
1545 
1546   Input Parameters:
1547 + mesh - The DMPlex
1548 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1549 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1550 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1551 
1552   Output Parameters:
1553 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1554 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1555 
1556   Note:
1557   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1558 
1559   Level: beginner
1560 
1561 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1562 @*/
1563 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1564 {
1565   DM_Plex     *mesh = (DM_Plex *) dm->data;
1566   PetscInt       *closure, *fifo;
1567   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1568   PetscInt        tmpSize, t;
1569   PetscInt        depth = 0, maxSize;
1570   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1571   PetscErrorCode  ierr;
1572 
1573   PetscFunctionBegin;
1574   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1575   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1576   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1577   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1578   if (*points) {
1579     closure = *points;
1580   } else {
1581     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1582   }
1583   closure[0] = p; closure[1] = 0;
1584   /* This is only 1-level */
1585   if (useCone) {
1586     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1587     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1588     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1589   } else {
1590     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1591     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1592   }
1593   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1594     const PetscInt cp = tmp[t];
1595     const PetscInt co = tmpO ? tmpO[t] : 0;
1596 
1597     closure[closureSize]   = cp;
1598     closure[closureSize+1] = co;
1599     fifo[fifoSize]         = cp;
1600     fifo[fifoSize+1]       = co;
1601   }
1602   while(fifoSize - fifoStart) {
1603     const PetscInt q   = fifo[fifoStart];
1604     const PetscInt o   = fifo[fifoStart+1];
1605     const PetscInt rev = o >= 0 ? 0 : 1;
1606     const PetscInt off = rev ? -(o+1) : o;
1607 
1608     if (useCone) {
1609       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1610       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1611       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1612     } else {
1613       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1614       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1615       tmpO = PETSC_NULL;
1616     }
1617     for (t = 0; t < tmpSize; ++t) {
1618       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1619       const PetscInt cp = tmp[i];
1620       /* Must propogate orientation */
1621       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1622       PetscInt       c;
1623 
1624       /* Check for duplicate */
1625       for (c = 0; c < closureSize; c += 2) {
1626         if (closure[c] == cp) break;
1627       }
1628       if (c == closureSize) {
1629         closure[closureSize]   = cp;
1630         closure[closureSize+1] = co;
1631         fifo[fifoSize]         = cp;
1632         fifo[fifoSize+1]       = co;
1633         closureSize += 2;
1634         fifoSize    += 2;
1635       }
1636     }
1637     fifoStart += 2;
1638   }
1639   if (numPoints) *numPoints = closureSize/2;
1640   if (points)    *points    = closure;
1641   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1642   PetscFunctionReturn(0);
1643 }
1644 
1645 #undef __FUNCT__
1646 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1647 /*@C
1648   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1649 
1650   Not collective
1651 
1652   Input Parameters:
1653 + mesh - The DMPlex
1654 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1655 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1656 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1657 
1658   Output Parameters:
1659 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1660 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1661 
1662   Note:
1663   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1664 
1665   Level: beginner
1666 
1667 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1668 @*/
1669 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1670 {
1671   PetscErrorCode  ierr;
1672 
1673   PetscFunctionBegin;
1674   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1675   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1676   PetscFunctionReturn(0);
1677 }
1678 
1679 #undef __FUNCT__
1680 #define __FUNCT__ "DMPlexGetFaces"
1681 /*
1682   DMPlexGetFaces -
1683 
1684   Note: This will only work for cell-vertex meshes.
1685 */
1686 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1687 {
1688   DM_Plex     *mesh  = (DM_Plex *) dm->data;
1689   const PetscInt *cone  = PETSC_NULL;
1690   PetscInt        depth = 0, dim, coneSize;
1691   PetscErrorCode  ierr;
1692 
1693   PetscFunctionBegin;
1694   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1695   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1696   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1697   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1698   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1699   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1700   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1701   switch(dim) {
1702   case 2:
1703     switch(coneSize) {
1704     case 3:
1705       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1706       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1707       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1708       *numFaces = 3;
1709       *faceSize = 2;
1710       *faces    = mesh->facesTmp;
1711       break;
1712     case 4:
1713       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1714       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1715       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1716       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1717       *numFaces = 4;
1718       *faceSize = 2;
1719       *faces    = mesh->facesTmp;
1720       break;
1721     default:
1722       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1723     }
1724     break;
1725   case 3:
1726     switch(coneSize) {
1727     case 3:
1728       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1729       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1730       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1731       *numFaces = 3;
1732       *faceSize = 2;
1733       *faces    = mesh->facesTmp;
1734       break;
1735     case 4:
1736       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1737       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1738       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1739       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1740       *numFaces = 4;
1741       *faceSize = 3;
1742       *faces    = mesh->facesTmp;
1743       break;
1744     default:
1745       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1746     }
1747     break;
1748   default:
1749     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1750   }
1751   PetscFunctionReturn(0);
1752 }
1753 
1754 #undef __FUNCT__
1755 #define __FUNCT__ "DMPlexGetMaxSizes"
1756 /*@
1757   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1758 
1759   Not collective
1760 
1761   Input Parameter:
1762 . mesh - The DMPlex
1763 
1764   Output Parameters:
1765 + maxConeSize - The maximum number of in-edges
1766 - maxSupportSize - The maximum number of out-edges
1767 
1768   Level: beginner
1769 
1770 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1771 @*/
1772 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1773 {
1774   DM_Plex *mesh = (DM_Plex *) dm->data;
1775 
1776   PetscFunctionBegin;
1777   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1778   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1779   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1780   PetscFunctionReturn(0);
1781 }
1782 
1783 #undef __FUNCT__
1784 #define __FUNCT__ "DMSetUp_Plex"
1785 PetscErrorCode DMSetUp_Plex(DM dm)
1786 {
1787   DM_Plex    *mesh = (DM_Plex *) dm->data;
1788   PetscInt       size;
1789   PetscErrorCode ierr;
1790 
1791   PetscFunctionBegin;
1792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1793   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1794   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1795   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1796   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1797   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1798   if (mesh->maxSupportSize) {
1799     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1800     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1801     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1802   }
1803   PetscFunctionReturn(0);
1804 }
1805 
1806 #undef __FUNCT__
1807 #define __FUNCT__ "DMCreateSubDM_Plex"
1808 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1809 {
1810   PetscSection   section, sectionGlobal;
1811   PetscInt      *subIndices;
1812   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1813   PetscErrorCode ierr;
1814 
1815   PetscFunctionBegin;
1816   if (!numFields) PetscFunctionReturn(0);
1817   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1818   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1819   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1820   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1821   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1822   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);
1823   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1824   for (p = pStart; p < pEnd; ++p) {
1825     PetscInt gdof;
1826 
1827     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1828     if (gdof > 0) {
1829       for (f = 0; f < numFields; ++f) {
1830         PetscInt fdof, fcdof;
1831 
1832         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1833         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1834         subSize += fdof-fcdof;
1835       }
1836     }
1837   }
1838   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1839   for (p = pStart; p < pEnd; ++p) {
1840     PetscInt gdof, goff;
1841 
1842     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1843     if (gdof > 0) {
1844       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1845       for (f = 0; f < numFields; ++f) {
1846         PetscInt fdof, fcdof, fc, f2, poff = 0;
1847 
1848         /* Can get rid of this loop by storing field information in the global section */
1849         for (f2 = 0; f2 < fields[f]; ++f2) {
1850           ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1851           ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1852           poff += fdof-fcdof;
1853         }
1854         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1855         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1856         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1857           subIndices[subOff] = goff+poff+fc;
1858         }
1859       }
1860     }
1861   }
1862   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1863   if (subdm) {
1864     PetscSection subsection;
1865     PetscBool    haveNull = PETSC_FALSE;
1866     PetscInt     f, nf = 0;
1867 
1868     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1869     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1870     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1871     for (f = 0; f < numFields; ++f) {
1872       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1873       if ((*subdm)->nullspaceConstructors[f]) {
1874         haveNull = PETSC_TRUE;
1875         nf       = f;
1876       }
1877     }
1878     if (haveNull) {
1879       MatNullSpace nullSpace;
1880 
1881       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1882       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1883       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1884     }
1885     if (dm->fields) {
1886       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);
1887       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1888       for (f = 0; f < numFields; ++f) {
1889         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1890       }
1891       if (numFields == 1) {
1892         MatNullSpace space;
1893         Mat          pmat;
1894 
1895         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject *) &space);CHKERRQ(ierr);
1896         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1897         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject *) &space);CHKERRQ(ierr);
1898         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1899         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject *) &pmat);CHKERRQ(ierr);
1900         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1901       }
1902     }
1903   }
1904   PetscFunctionReturn(0);
1905 }
1906 
1907 #undef __FUNCT__
1908 #define __FUNCT__ "DMPlexSymmetrize"
1909 /*@
1910   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1911 
1912   Not collective
1913 
1914   Input Parameter:
1915 . mesh - The DMPlex
1916 
1917   Output Parameter:
1918 
1919   Note:
1920   This should be called after all calls to DMPlexSetCone()
1921 
1922   Level: beginner
1923 
1924 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1925 @*/
1926 PetscErrorCode DMPlexSymmetrize(DM dm)
1927 {
1928   DM_Plex    *mesh = (DM_Plex *) dm->data;
1929   PetscInt      *offsets;
1930   PetscInt       supportSize;
1931   PetscInt       pStart, pEnd, p;
1932   PetscErrorCode ierr;
1933 
1934   PetscFunctionBegin;
1935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1936   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1937   /* Calculate support sizes */
1938   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1939   for (p = pStart; p < pEnd; ++p) {
1940     PetscInt dof, off, c;
1941 
1942     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1943     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1944     for (c = off; c < off+dof; ++c) {
1945       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1946     }
1947   }
1948   for (p = pStart; p < pEnd; ++p) {
1949     PetscInt dof;
1950 
1951     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1952     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1953   }
1954   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1955   /* Calculate supports */
1956   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1957   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1958   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1959   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1960   for (p = pStart; p < pEnd; ++p) {
1961     PetscInt dof, off, c;
1962 
1963     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1964     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1965     for (c = off; c < off+dof; ++c) {
1966       const PetscInt q = mesh->cones[c];
1967       PetscInt       offS;
1968 
1969       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1970       mesh->supports[offS+offsets[q]] = p;
1971       ++offsets[q];
1972     }
1973   }
1974   ierr = PetscFree(offsets);CHKERRQ(ierr);
1975   PetscFunctionReturn(0);
1976 }
1977 
1978 #undef __FUNCT__
1979 #define __FUNCT__ "DMPlexSetDepth_Private"
1980 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1981 {
1982   PetscInt       d;
1983   PetscErrorCode ierr;
1984 
1985   PetscFunctionBegin;
1986   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1987   if (d < 0) {
1988     /* We are guaranteed that the point has a cone since the depth was not yet set */
1989     const PetscInt *cone = PETSC_NULL;
1990     PetscInt        dCone;
1991 
1992     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1993     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1994     d    = dCone+1;
1995     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1996   }
1997   *depth = d;
1998   PetscFunctionReturn(0);
1999 }
2000 
2001 #undef __FUNCT__
2002 #define __FUNCT__ "DMPlexStratify"
2003 /*@
2004   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2005   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2006   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2007   the DAG.
2008 
2009   Not collective
2010 
2011   Input Parameter:
2012 . mesh - The DMPlex
2013 
2014   Output Parameter:
2015 
2016   Notes:
2017   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2018   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2019 
2020   This should be called after all calls to DMPlexSymmetrize()
2021 
2022   Level: beginner
2023 
2024 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2025 @*/
2026 PetscErrorCode DMPlexStratify(DM dm)
2027 {
2028   DM_Plex    *mesh = (DM_Plex *) dm->data;
2029   PetscInt       pStart, pEnd, p;
2030   PetscInt       numRoots = 0, numLeaves = 0;
2031   PetscErrorCode ierr;
2032 
2033   PetscFunctionBegin;
2034   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2035   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2036   /* Calculate depth */
2037   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2038   /* Initialize roots and count leaves */
2039   for (p = pStart; p < pEnd; ++p) {
2040     PetscInt coneSize, supportSize;
2041 
2042     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2043     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2044     if (!coneSize && supportSize) {
2045       ++numRoots;
2046       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2047     } else if (!supportSize && coneSize) {
2048       ++numLeaves;
2049     } else if (!supportSize && !coneSize) {
2050       /* Isolated points */
2051       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2052     }
2053   }
2054   if (numRoots + numLeaves == (pEnd - pStart)) {
2055     for (p = pStart; p < pEnd; ++p) {
2056       PetscInt coneSize, supportSize;
2057 
2058       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2059       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2060       if (!supportSize && coneSize) {
2061         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2062       }
2063     }
2064   } else {
2065     /* This might be slow since lookup is not fast */
2066     for (p = pStart; p < pEnd; ++p) {
2067       PetscInt depth;
2068 
2069       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2070     }
2071   }
2072   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2073   PetscFunctionReturn(0);
2074 }
2075 
2076 #undef __FUNCT__
2077 #define __FUNCT__ "DMPlexGetJoin"
2078 /*@C
2079   DMPlexGetJoin - Get an array for the join of the set of points
2080 
2081   Not Collective
2082 
2083   Input Parameters:
2084 + dm - The DMPlex object
2085 . numPoints - The number of input points for the join
2086 - points - The input points
2087 
2088   Output Parameters:
2089 + numCoveredPoints - The number of points in the join
2090 - coveredPoints - The points in the join
2091 
2092   Level: intermediate
2093 
2094   Note: Currently, this is restricted to a single level join
2095 
2096 .keywords: mesh
2097 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2098 @*/
2099 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2100 {
2101   DM_Plex    *mesh = (DM_Plex *) dm->data;
2102   PetscInt      *join[2];
2103   PetscInt       joinSize, i = 0;
2104   PetscInt       dof, off, p, c, m;
2105   PetscErrorCode ierr;
2106 
2107   PetscFunctionBegin;
2108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2109   PetscValidPointer(points, 2);
2110   PetscValidPointer(numCoveredPoints, 3);
2111   PetscValidPointer(coveredPoints, 4);
2112   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2113   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2114   /* Copy in support of first point */
2115   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2116   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2117   for (joinSize = 0; joinSize < dof; ++joinSize) {
2118     join[i][joinSize] = mesh->supports[off+joinSize];
2119   }
2120   /* Check each successive support */
2121   for (p = 1; p < numPoints; ++p) {
2122     PetscInt newJoinSize = 0;
2123 
2124     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2125     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2126     for (c = 0; c < dof; ++c) {
2127       const PetscInt point = mesh->supports[off+c];
2128 
2129       for (m = 0; m < joinSize; ++m) {
2130         if (point == join[i][m]) {
2131           join[1-i][newJoinSize++] = point;
2132           break;
2133         }
2134       }
2135     }
2136     joinSize = newJoinSize;
2137     i = 1-i;
2138   }
2139   *numCoveredPoints = joinSize;
2140   *coveredPoints    = join[i];
2141   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2142   PetscFunctionReturn(0);
2143 }
2144 
2145 #undef __FUNCT__
2146 #define __FUNCT__ "DMPlexRestoreJoin"
2147 /*@C
2148   DMPlexRestoreJoin - Restore an array for the join of the set of points
2149 
2150   Not Collective
2151 
2152   Input Parameters:
2153 + dm - The DMPlex object
2154 . numPoints - The number of input points for the join
2155 - points - The input points
2156 
2157   Output Parameters:
2158 + numCoveredPoints - The number of points in the join
2159 - coveredPoints - The points in the join
2160 
2161   Level: intermediate
2162 
2163 .keywords: mesh
2164 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2165 @*/
2166 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2167 {
2168   PetscErrorCode ierr;
2169 
2170   PetscFunctionBegin;
2171   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2172   PetscValidPointer(coveredPoints, 4);
2173   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2174   PetscFunctionReturn(0);
2175 }
2176 
2177 #undef __FUNCT__
2178 #define __FUNCT__ "DMPlexGetFullJoin"
2179 /*@C
2180   DMPlexGetFullJoin - Get an array for the join of the set of points
2181 
2182   Not Collective
2183 
2184   Input Parameters:
2185 + dm - The DMPlex object
2186 . numPoints - The number of input points for the join
2187 - points - The input points
2188 
2189   Output Parameters:
2190 + numCoveredPoints - The number of points in the join
2191 - coveredPoints - The points in the join
2192 
2193   Level: intermediate
2194 
2195 .keywords: mesh
2196 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2197 @*/
2198 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2199 {
2200   DM_Plex    *mesh = (DM_Plex *) dm->data;
2201   PetscInt      *offsets, **closures;
2202   PetscInt      *join[2];
2203   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2204   PetscInt       p, d, c, m;
2205   PetscErrorCode ierr;
2206 
2207   PetscFunctionBegin;
2208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2209   PetscValidPointer(points, 2);
2210   PetscValidPointer(numCoveredPoints, 3);
2211   PetscValidPointer(coveredPoints, 4);
2212 
2213   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2214   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2215   ierr = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2216   ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2217   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2218   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2219   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2220 
2221   for (p = 0; p < numPoints; ++p) {
2222     PetscInt closureSize;
2223 
2224     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2225     offsets[p*(depth+2)+0] = 0;
2226     for (d = 0; d < depth+1; ++d) {
2227       PetscInt pStart, pEnd, i;
2228 
2229       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2230       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2231         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2232           offsets[p*(depth+2)+d+1] = i;
2233           break;
2234         }
2235       }
2236       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2237     }
2238     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);
2239   }
2240   for (d = 0; d < depth+1; ++d) {
2241     PetscInt dof;
2242 
2243     /* Copy in support of first point */
2244     dof = offsets[d+1] - offsets[d];
2245     for (joinSize = 0; joinSize < dof; ++joinSize) {
2246       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2247     }
2248     /* Check each successive cone */
2249     for (p = 1; p < numPoints && joinSize; ++p) {
2250       PetscInt newJoinSize = 0;
2251 
2252       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2253       for (c = 0; c < dof; ++c) {
2254         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2255 
2256         for (m = 0; m < joinSize; ++m) {
2257           if (point == join[i][m]) {
2258             join[1-i][newJoinSize++] = point;
2259             break;
2260           }
2261         }
2262       }
2263       joinSize = newJoinSize;
2264       i = 1-i;
2265     }
2266     if (joinSize) break;
2267   }
2268   *numCoveredPoints = joinSize;
2269   *coveredPoints    = join[i];
2270   for (p = 0; p < numPoints; ++p) {
2271     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2272   }
2273   ierr = PetscFree(closures);CHKERRQ(ierr);
2274   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2275   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2276   PetscFunctionReturn(0);
2277 }
2278 
2279 #undef __FUNCT__
2280 #define __FUNCT__ "DMPlexGetMeet"
2281 /*@C
2282   DMPlexGetMeet - Get an array for the meet of the set of points
2283 
2284   Not Collective
2285 
2286   Input Parameters:
2287 + dm - The DMPlex object
2288 . numPoints - The number of input points for the meet
2289 - points - The input points
2290 
2291   Output Parameters:
2292 + numCoveredPoints - The number of points in the meet
2293 - coveredPoints - The points in the meet
2294 
2295   Level: intermediate
2296 
2297   Note: Currently, this is restricted to a single level meet
2298 
2299 .keywords: mesh
2300 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2301 @*/
2302 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2303 {
2304   DM_Plex    *mesh = (DM_Plex *) dm->data;
2305   PetscInt      *meet[2];
2306   PetscInt       meetSize, i = 0;
2307   PetscInt       dof, off, p, c, m;
2308   PetscErrorCode ierr;
2309 
2310   PetscFunctionBegin;
2311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2312   PetscValidPointer(points, 2);
2313   PetscValidPointer(numCoveringPoints, 3);
2314   PetscValidPointer(coveringPoints, 4);
2315   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2316   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2317   /* Copy in cone of first point */
2318   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2319   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2320   for (meetSize = 0; meetSize < dof; ++meetSize) {
2321     meet[i][meetSize] = mesh->cones[off+meetSize];
2322   }
2323   /* Check each successive cone */
2324   for (p = 1; p < numPoints; ++p) {
2325     PetscInt newMeetSize = 0;
2326 
2327     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2328     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2329     for (c = 0; c < dof; ++c) {
2330       const PetscInt point = mesh->cones[off+c];
2331 
2332       for (m = 0; m < meetSize; ++m) {
2333         if (point == meet[i][m]) {
2334           meet[1-i][newMeetSize++] = point;
2335           break;
2336         }
2337       }
2338     }
2339     meetSize = newMeetSize;
2340     i = 1-i;
2341   }
2342   *numCoveringPoints = meetSize;
2343   *coveringPoints    = meet[i];
2344   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2345   PetscFunctionReturn(0);
2346 }
2347 
2348 #undef __FUNCT__
2349 #define __FUNCT__ "DMPlexRestoreMeet"
2350 /*@C
2351   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2352 
2353   Not Collective
2354 
2355   Input Parameters:
2356 + dm - The DMPlex object
2357 . numPoints - The number of input points for the meet
2358 - points - The input points
2359 
2360   Output Parameters:
2361 + numCoveredPoints - The number of points in the meet
2362 - coveredPoints - The points in the meet
2363 
2364   Level: intermediate
2365 
2366 .keywords: mesh
2367 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2368 @*/
2369 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2370 {
2371   PetscErrorCode ierr;
2372 
2373   PetscFunctionBegin;
2374   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2375   PetscValidPointer(coveredPoints, 4);
2376   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2377   PetscFunctionReturn(0);
2378 }
2379 
2380 #undef __FUNCT__
2381 #define __FUNCT__ "DMPlexGetFullMeet"
2382 /*@C
2383   DMPlexGetFullMeet - Get an array for the meet of the set of points
2384 
2385   Not Collective
2386 
2387   Input Parameters:
2388 + dm - The DMPlex object
2389 . numPoints - The number of input points for the meet
2390 - points - The input points
2391 
2392   Output Parameters:
2393 + numCoveredPoints - The number of points in the meet
2394 - coveredPoints - The points in the meet
2395 
2396   Level: intermediate
2397 
2398 .keywords: mesh
2399 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2400 @*/
2401 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2402 {
2403   DM_Plex    *mesh = (DM_Plex *) dm->data;
2404   PetscInt      *offsets, **closures;
2405   PetscInt      *meet[2];
2406   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2407   PetscInt       p, h, c, m;
2408   PetscErrorCode ierr;
2409 
2410   PetscFunctionBegin;
2411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2412   PetscValidPointer(points, 2);
2413   PetscValidPointer(numCoveredPoints, 3);
2414   PetscValidPointer(coveredPoints, 4);
2415 
2416   ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2417   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2418   ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2419   maxSize = PetscPowInt(mesh->maxConeSize,height);
2420   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2421   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2422 
2423   for (p = 0; p < numPoints; ++p) {
2424     PetscInt closureSize;
2425 
2426     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2427     offsets[p*(height+2)+0] = 0;
2428     for (h = 0; h < height+1; ++h) {
2429       PetscInt pStart, pEnd, i;
2430 
2431       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2432       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2433         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2434           offsets[p*(height+2)+h+1] = i;
2435           break;
2436         }
2437       }
2438       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2439     }
2440     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);
2441   }
2442   for (h = 0; h < height+1; ++h) {
2443     PetscInt dof;
2444 
2445     /* Copy in cone of first point */
2446     dof = offsets[h+1] - offsets[h];
2447     for (meetSize = 0; meetSize < dof; ++meetSize) {
2448       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2449     }
2450     /* Check each successive cone */
2451     for (p = 1; p < numPoints && meetSize; ++p) {
2452       PetscInt newMeetSize = 0;
2453 
2454       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2455       for (c = 0; c < dof; ++c) {
2456         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2457 
2458         for (m = 0; m < meetSize; ++m) {
2459           if (point == meet[i][m]) {
2460             meet[1-i][newMeetSize++] = point;
2461             break;
2462           }
2463         }
2464       }
2465       meetSize = newMeetSize;
2466       i = 1-i;
2467     }
2468     if (meetSize) break;
2469   }
2470   *numCoveredPoints = meetSize;
2471   *coveredPoints    = meet[i];
2472   for (p = 0; p < numPoints; ++p) {
2473     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2474   }
2475   ierr = PetscFree(closures);CHKERRQ(ierr);
2476   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2477   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2478   PetscFunctionReturn(0);
2479 }
2480 
2481 #undef __FUNCT__
2482 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2483 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2484 {
2485   MPI_Comm       comm = ((PetscObject) dm)->comm;
2486   PetscInt       cellDim;
2487   PetscErrorCode ierr;
2488 
2489   PetscFunctionBegin;
2490   PetscValidPointer(numFaceVertices,3);
2491   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2492   switch(cellDim) {
2493   case 0:
2494     *numFaceVertices = 0;
2495     break;
2496   case 1:
2497     *numFaceVertices = 1;
2498     break;
2499   case 2:
2500     switch(numCorners) {
2501     case 3: /* triangle */
2502       *numFaceVertices = 2; /* Edge has 2 vertices */
2503       break;
2504     case 4: /* quadrilateral */
2505       *numFaceVertices = 2; /* Edge has 2 vertices */
2506       break;
2507     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2508       *numFaceVertices = 3; /* Edge has 3 vertices */
2509       break;
2510     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2511       *numFaceVertices = 3; /* Edge has 3 vertices */
2512       break;
2513     default:
2514       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2515     }
2516     break;
2517   case 3:
2518     switch(numCorners) {
2519     case 4: /* tetradehdron */
2520       *numFaceVertices = 3; /* Face has 3 vertices */
2521       break;
2522     case 6: /* tet cohesive cells */
2523       *numFaceVertices = 4; /* Face has 4 vertices */
2524       break;
2525     case 8: /* hexahedron */
2526       *numFaceVertices = 4; /* Face has 4 vertices */
2527       break;
2528     case 9: /* tet cohesive Lagrange cells */
2529       *numFaceVertices = 6; /* Face has 6 vertices */
2530       break;
2531     case 10: /* quadratic tetrahedron */
2532       *numFaceVertices = 6; /* Face has 6 vertices */
2533       break;
2534     case 12: /* hex cohesive Lagrange cells */
2535       *numFaceVertices = 6; /* Face has 6 vertices */
2536       break;
2537     case 18: /* quadratic tet cohesive Lagrange cells */
2538       *numFaceVertices = 6; /* Face has 6 vertices */
2539       break;
2540     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2541       *numFaceVertices = 9; /* Face has 9 vertices */
2542       break;
2543     default:
2544       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2545     }
2546     break;
2547   default:
2548     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2549   }
2550   PetscFunctionReturn(0);
2551 }
2552 
2553 #undef __FUNCT__
2554 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2555 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2556 {
2557   const PetscInt maxFaceCases = 30;
2558   PetscInt       numFaceCases = 0;
2559   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2560   PetscInt      *off, *adj;
2561   PetscInt      *neighborCells, *tmpClosure;
2562   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2563   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2564   PetscErrorCode ierr;
2565 
2566   PetscFunctionBegin;
2567   /* For parallel partitioning, I think you have to communicate supports */
2568   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2569   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2570   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2571   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2572   if (cEnd - cStart == 0) {
2573     if (numVertices) *numVertices = 0;
2574     if (offsets)     *offsets     = PETSC_NULL;
2575     if (adjacency)   *adjacency   = PETSC_NULL;
2576     PetscFunctionReturn(0);
2577   }
2578   numCells = cEnd - cStart;
2579   /* Setup face recognition */
2580   {
2581     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 */
2582 
2583     for (c = cStart; c < cEnd; ++c) {
2584       PetscInt corners;
2585 
2586       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2587       if (!cornersSeen[corners]) {
2588         PetscInt nFV;
2589 
2590         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2591         cornersSeen[corners] = 1;
2592         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2593         numFaceVertices[numFaceCases++] = nFV;
2594       }
2595     }
2596   }
2597   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2598   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2599   ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2600   ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2601   ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2602   /* Count neighboring cells */
2603   for (cell = cStart; cell < cEnd; ++cell) {
2604     PetscInt numNeighbors = maxNeighbors, n;
2605 
2606     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2607     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2608     for (n = 0; n < numNeighbors; ++n) {
2609       PetscInt        cellPair[2] = {cell, neighborCells[n]};
2610       PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2611       PetscInt        meetSize    = 0;
2612       const PetscInt *meet        = PETSC_NULL;
2613 
2614       if (cellPair[0] == cellPair[1]) continue;
2615       if (!found) {
2616         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2617         if (meetSize) {
2618           PetscInt f;
2619 
2620           for (f = 0; f < numFaceCases; ++f) {
2621             if (numFaceVertices[f] == meetSize) {
2622               found = PETSC_TRUE;
2623               break;
2624             }
2625           }
2626         }
2627         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2628       }
2629       if (found) {
2630         ++off[cell-cStart+1];
2631       }
2632     }
2633   }
2634   /* Prefix sum */
2635   for (cell = 1; cell <= numCells; ++cell) {
2636     off[cell] += off[cell-1];
2637   }
2638   if (adjacency) {
2639     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2640     /* Get neighboring cells */
2641     for (cell = cStart; cell < cEnd; ++cell) {
2642       PetscInt numNeighbors = maxNeighbors, n;
2643       PetscInt cellOffset   = 0;
2644 
2645       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2646       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2647       for (n = 0; n < numNeighbors; ++n) {
2648         PetscInt        cellPair[2] = {cell, neighborCells[n]};
2649         PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2650         PetscInt        meetSize    = 0;
2651         const PetscInt *meet        = PETSC_NULL;
2652 
2653         if (cellPair[0] == cellPair[1]) continue;
2654         if (!found) {
2655           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2656           if (meetSize) {
2657             PetscInt f;
2658 
2659             for (f = 0; f < numFaceCases; ++f) {
2660               if (numFaceVertices[f] == meetSize) {
2661                 found = PETSC_TRUE;
2662                 break;
2663               }
2664             }
2665           }
2666           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2667         }
2668         if (found) {
2669           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2670           ++cellOffset;
2671         }
2672       }
2673     }
2674   }
2675   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2676   if (numVertices) *numVertices = numCells;
2677   if (offsets)     *offsets     = off;
2678   if (adjacency)   *adjacency   = adj;
2679   PetscFunctionReturn(0);
2680 }
2681 
2682 #ifdef PETSC_HAVE_CHACO
2683 #ifdef PETSC_HAVE_UNISTD_H
2684 #include <unistd.h>
2685 #endif
2686 /* Chaco does not have an include file */
2687 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2688                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2689                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2690                        int mesh_dims[3], double *goal, int global_method, int local_method,
2691                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2692 
2693 extern int FREE_GRAPH;
2694 
2695 #undef __FUNCT__
2696 #define __FUNCT__ "DMPlexPartition_Chaco"
2697 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2698 {
2699   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2700   MPI_Comm comm = ((PetscObject) dm)->comm;
2701   int nvtxs = numVertices;                /* number of vertices in full graph */
2702   int *vwgts = NULL;                      /* weights for all vertices */
2703   float *ewgts = NULL;                    /* weights for all edges */
2704   float *x = NULL, *y = NULL, *z = NULL;  /* coordinates for inertial method */
2705   char *outassignname = NULL;             /*  name of assignment output file */
2706   char *outfilename = NULL;               /* output file name */
2707   int architecture = 1;                   /* 0 => hypercube, d => d-dimensional mesh */
2708   int ndims_tot = 0;                      /* total number of cube dimensions to divide */
2709   int mesh_dims[3];                       /* dimensions of mesh of processors */
2710   double *goal = NULL;                    /* desired set sizes for each set */
2711   int global_method = 1;                  /* global partitioning algorithm */
2712   int local_method = 1;                   /* local partitioning algorithm */
2713   int rqi_flag = 0;                       /* should I use RQI/Symmlq eigensolver? */
2714   int vmax = 200;                         /* how many vertices to coarsen down to? */
2715   int ndims = 1;                          /* number of eigenvectors (2^d sets) */
2716   double eigtol = 0.001;                  /* tolerance on eigenvectors */
2717   long seed = 123636512;                  /* for random graph mutations */
2718   short int *assignment;                  /* Output partition */
2719   int fd_stdout, fd_pipe[2];
2720   PetscInt      *points;
2721   PetscMPIInt    commSize;
2722   int            i, v, p;
2723   PetscErrorCode ierr;
2724 
2725   PetscFunctionBegin;
2726   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2727   if (!numVertices) {
2728     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2729     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2730     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2731     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2732     PetscFunctionReturn(0);
2733   }
2734   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2735   for (i = 0; i < start[numVertices]; ++i) {
2736     ++adjacency[i];
2737   }
2738   if (global_method == INERTIAL_METHOD) {
2739     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2740     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2741   }
2742   mesh_dims[0] = commSize;
2743   mesh_dims[1] = 1;
2744   mesh_dims[2] = 1;
2745   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2746   /* Chaco outputs to stdout. We redirect this to a buffer. */
2747   /* TODO: check error codes for UNIX calls */
2748 #ifdef PETSC_HAVE_UNISTD_H
2749   {
2750     int piperet;
2751     piperet = pipe(fd_pipe);
2752     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2753     fd_stdout = dup(1);
2754     close(1);
2755     dup2(fd_pipe[1], 1);
2756   }
2757 #endif
2758   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2759                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2760                    vmax, ndims, eigtol, seed);
2761 #ifdef PETSC_HAVE_UNISTD_H
2762   {
2763     char msgLog[10000];
2764     int  count;
2765 
2766     fflush(stdout);
2767     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2768     if (count < 0) count = 0;
2769     msgLog[count] = 0;
2770     close(1);
2771     dup2(fd_stdout, 1);
2772     close(fd_stdout);
2773     close(fd_pipe[0]);
2774     close(fd_pipe[1]);
2775     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2776   }
2777 #endif
2778   /* Convert to PetscSection+IS */
2779   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2780   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2781   for (v = 0; v < nvtxs; ++v) {
2782     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2783   }
2784   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2785   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2786   for (p = 0, i = 0; p < commSize; ++p) {
2787     for (v = 0; v < nvtxs; ++v) {
2788       if (assignment[v] == p) points[i++] = v;
2789     }
2790   }
2791   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2792   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2793   if (global_method == INERTIAL_METHOD) {
2794     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2795   }
2796   ierr = PetscFree(assignment);CHKERRQ(ierr);
2797   for (i = 0; i < start[numVertices]; ++i) {
2798     --adjacency[i];
2799   }
2800   PetscFunctionReturn(0);
2801 }
2802 #endif
2803 
2804 #ifdef PETSC_HAVE_PARMETIS
2805 #undef __FUNCT__
2806 #define __FUNCT__ "DMPlexPartition_ParMetis"
2807 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2808 {
2809   PetscFunctionBegin;
2810   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2811   PetscFunctionReturn(0);
2812 }
2813 #endif
2814 
2815 #undef __FUNCT__
2816 #define __FUNCT__ "DMPlexEnlargePartition"
2817 /* Expand the partition by BFS on the adjacency graph */
2818 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2819 {
2820   PetscHashI      h;
2821   const PetscInt *points;
2822   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2823   PetscInt        pStart, pEnd, part, q;
2824   PetscErrorCode  ierr;
2825 
2826   PetscFunctionBegin;
2827   PetscHashICreate(h);
2828   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2829   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2830   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2831   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2832   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2833   for(part = pStart; part < pEnd; ++part) {
2834     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2835 
2836     PetscHashIClear(h);
2837     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2838     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2839     /* Add all existing points to h */
2840     for(p = 0; p < numPoints; ++p) {
2841       const PetscInt point = points[off+p];
2842       PetscHashIAdd(h, point, 1);
2843     }
2844     PetscHashISize(h, nP);
2845     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2846     /* Add all points in next BFS level */
2847     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2848     for(p = 0; p < numPoints; ++p) {
2849       const PetscInt point = points[off+p];
2850       PetscInt s = start[point], e = start[point+1], a;
2851 
2852       for(a = s; a < e; ++a) {
2853         PetscHashIAdd(h, adjacency[a], 1);
2854       }
2855     }
2856     PetscHashISize(h, numNewPoints);
2857     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2858     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2859     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2860     totPoints += numNewPoints;
2861   }
2862   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2863   PetscHashIDestroy(h);
2864   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2865   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2866   for(part = pStart, q = 0; part < pEnd; ++part) {
2867     PetscInt numPoints, p;
2868 
2869     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2870     for(p = 0; p < numPoints; ++p, ++q) {
2871       newPoints[q] = tmpPoints[part][p];
2872     }
2873     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2874   }
2875   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2876   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2877   PetscFunctionReturn(0);
2878 }
2879 
2880 #undef __FUNCT__
2881 #define __FUNCT__ "DMPlexCreatePartition"
2882 /*
2883   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2884 
2885   Collective on DM
2886 
2887   Input Parameters:
2888   + dm - The DM
2889   . height - The height for points in the partition
2890   - enlarge - Expand each partition with neighbors
2891 
2892   Output Parameters:
2893   + partSection - The PetscSection giving the division of points by partition
2894   . partition - The list of points by partition
2895   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2896   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2897 
2898   Level: developer
2899 
2900 .seealso DMPlexDistribute()
2901 */
2902 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2903 {
2904   PetscMPIInt    size;
2905   PetscErrorCode ierr;
2906 
2907   PetscFunctionBegin;
2908   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2909   *origPartSection = PETSC_NULL;
2910   *origPartition   = PETSC_NULL;
2911   if (size == 1) {
2912     PetscInt *points;
2913     PetscInt  cStart, cEnd, c;
2914 
2915     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2916     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2917     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2918     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2919     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2920     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2921     for (c = cStart; c < cEnd; ++c) {
2922       points[c] = c;
2923     }
2924     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2925     PetscFunctionReturn(0);
2926   }
2927   if (height == 0) {
2928     PetscInt  numVertices;
2929     PetscInt *start     = PETSC_NULL;
2930     PetscInt *adjacency = PETSC_NULL;
2931 
2932     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2933     if (1) {
2934 #ifdef PETSC_HAVE_CHACO
2935       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2936 #endif
2937     } else {
2938 #ifdef PETSC_HAVE_PARMETIS
2939       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2940 #endif
2941     }
2942     if (enlarge) {
2943       *origPartSection = *partSection;
2944       *origPartition   = *partition;
2945       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2946     }
2947     ierr = PetscFree(start);CHKERRQ(ierr);
2948     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2949 # if 0
2950   } else if (height == 1) {
2951     /* Build the dual graph for faces and partition the hypergraph */
2952     PetscInt numEdges;
2953 
2954     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2955     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2956     destroyCSR(numEdges, start, adjacency);
2957 #endif
2958   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2959   PetscFunctionReturn(0);
2960 }
2961 
2962 #undef __FUNCT__
2963 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2964 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2965 {
2966   /* const PetscInt  height = 0; */
2967   const PetscInt *partArray;
2968   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2969   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2970   PetscErrorCode  ierr;
2971 
2972   PetscFunctionBegin;
2973   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2974   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2975   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2976   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2977   for (rank = rStart; rank < rEnd; ++rank) {
2978     PetscInt partSize = 0;
2979     PetscInt numPoints, offset, p;
2980 
2981     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2982     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2983     for (p = 0; p < numPoints; ++p) {
2984       PetscInt  point   = partArray[offset+p], closureSize, c;
2985       PetscInt *closure = PETSC_NULL;
2986 
2987       /* TODO Include support for height > 0 case */
2988       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2989       /* Merge into existing points */
2990       if (partSize+closureSize > maxPartSize) {
2991         PetscInt *tmpPoints;
2992 
2993         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2994         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2995         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2996         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2997         partPoints = tmpPoints;
2998       }
2999       for (c = 0; c < closureSize; ++c) {
3000         partPoints[partSize+c] = closure[c*2];
3001       }
3002       partSize += closureSize;
3003       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3004       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3005     }
3006     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3007   }
3008   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3009   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3010   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3011 
3012   for (rank = rStart; rank < rEnd; ++rank) {
3013     PetscInt partSize = 0, newOffset;
3014     PetscInt numPoints, offset, p;
3015 
3016     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3017     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3018     for (p = 0; p < numPoints; ++p) {
3019       PetscInt  point   = partArray[offset+p], closureSize, c;
3020       PetscInt *closure = PETSC_NULL;
3021 
3022       /* TODO Include support for height > 0 case */
3023       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3024       /* Merge into existing points */
3025       for (c = 0; c < closureSize; ++c) {
3026         partPoints[partSize+c] = closure[c*2];
3027       }
3028       partSize += closureSize;
3029       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3030       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3031     }
3032     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3033     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3034   }
3035   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3036   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3037   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3038   PetscFunctionReturn(0);
3039 }
3040 
3041 #undef __FUNCT__
3042 #define __FUNCT__ "DMPlexDistributeField"
3043 /*
3044   Input Parameters:
3045 . originalSection
3046 , originalVec
3047 
3048   Output Parameters:
3049 . newSection
3050 . newVec
3051 */
3052 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3053 {
3054   PetscSF         fieldSF;
3055   PetscInt       *remoteOffsets, fieldSize;
3056   PetscScalar    *originalValues, *newValues;
3057   PetscErrorCode  ierr;
3058 
3059   PetscFunctionBegin;
3060   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3061 
3062   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3063   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3064   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3065 
3066   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3067   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3068   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3069   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3070   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3071   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3072   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3073   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3074   PetscFunctionReturn(0);
3075 }
3076 
3077 #undef __FUNCT__
3078 #define __FUNCT__ "DMPlexDistribute"
3079 /*@C
3080   DMPlexDistribute - Distributes the mesh and any associated sections.
3081 
3082   Not Collective
3083 
3084   Input Parameter:
3085 + dm  - The original DMPlex object
3086 . partitioner - The partitioning package, or NULL for the default
3087 - overlap - The overlap of partitions, 0 is the default
3088 
3089   Output Parameter:
3090 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3091 
3092   Note: If the mesh was not distributed, the return value is PETSC_NULL
3093 
3094   Level: intermediate
3095 
3096 .keywords: mesh, elements
3097 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3098 @*/
3099 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3100 {
3101   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3102   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3103   const PetscInt height = 0;
3104   PetscInt       dim, numRemoteRanks;
3105   IS             origCellPart,        cellPart,        part;
3106   PetscSection   origCellPartSection, cellPartSection, partSection;
3107   PetscSFNode   *remoteRanks;
3108   PetscSF        partSF, pointSF, coneSF;
3109   ISLocalToGlobalMapping renumbering;
3110   PetscSection   originalConeSection, newConeSection;
3111   PetscInt      *remoteOffsets;
3112   PetscInt      *cones, *newCones, newConesSize;
3113   PetscBool      flg;
3114   PetscMPIInt    rank, numProcs, p;
3115   PetscErrorCode ierr;
3116 
3117   PetscFunctionBegin;
3118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3119   PetscValidPointer(dmParallel,4);
3120   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3121   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3122   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3123   *dmParallel = PETSC_NULL;
3124   if (numProcs == 1) PetscFunctionReturn(0);
3125 
3126   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3127   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3128   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3129   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3130   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3131   if (!rank) {
3132     numRemoteRanks = numProcs;
3133   } else {
3134     numRemoteRanks = 0;
3135   }
3136   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3137   for (p = 0; p < numRemoteRanks; ++p) {
3138     remoteRanks[p].rank  = p;
3139     remoteRanks[p].index = 0;
3140   }
3141   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3142   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3143   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3144   if (flg) {
3145     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3146     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3147     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3148     if (origCellPart) {
3149       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3150       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3151       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3152     }
3153     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3154   }
3155   /* Close the partition over the mesh */
3156   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3157   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3158   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3159   /* Create new mesh */
3160   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3161   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3162   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3163   pmesh = (DM_Plex *) (*dmParallel)->data;
3164   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3165   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3166   if (flg) {
3167     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3168     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3169     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3170     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3171     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3172     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3173   }
3174   /* Distribute cone section */
3175   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3176   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3177   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3178   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3179   {
3180     PetscInt pStart, pEnd, p;
3181 
3182     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3183     for (p = pStart; p < pEnd; ++p) {
3184       PetscInt coneSize;
3185       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3186       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3187     }
3188   }
3189   /* Communicate and renumber cones */
3190   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3191   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3192   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3193   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3194   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3195   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3196   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3197   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3198   if (flg) {
3199     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3200     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3201     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3202     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3203     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3204   }
3205   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3206   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3207   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3208   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3209   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3210   /* Create supports and stratify sieve */
3211   {
3212     PetscInt pStart, pEnd;
3213 
3214     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3215     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3216   }
3217   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3218   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3219   /* Distribute Coordinates */
3220   {
3221     PetscSection originalCoordSection, newCoordSection;
3222     Vec          originalCoordinates, newCoordinates;
3223     const char  *name;
3224 
3225     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3226     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3227     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3228     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3229     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3230     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3231 
3232     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3233     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3234     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3235   }
3236   /* Distribute labels */
3237   {
3238     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3239     PetscInt   numLabels = 0, l;
3240 
3241     /* Bcast number of labels */
3242     while(next) {++numLabels; next = next->next;}
3243     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3244     next = mesh->labels;
3245     for (l = 0; l < numLabels; ++l) {
3246       DMLabel         newLabel;
3247       const PetscInt *partArray;
3248       char           *name;
3249       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3250       PetscMPIInt    *sendcnts = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3251       PetscInt        nameSize, s, p;
3252       PetscBool       isdepth;
3253       size_t          len = 0;
3254 
3255       /* Bcast name (could filter for no points) */
3256       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3257       nameSize = len;
3258       ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3259       ierr = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3260       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3261       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3262       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3263       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3264       ierr = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3265       newLabel->name = name;
3266       /* Bcast numStrata (could filter for no points in stratum) */
3267       if (!rank) {newLabel->numStrata = next->numStrata;}
3268       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3269       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3270                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3271                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3272       /* Bcast stratumValues (could filter for no points in stratum) */
3273       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3274       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3275       /* Find size on each process and Scatter */
3276       if (!rank) {
3277         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3278         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3279         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3280         for (s = 0; s < next->numStrata; ++s) {
3281           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3282             const PetscInt point = next->points[p];
3283             PetscInt       proc;
3284 
3285             for (proc = 0; proc < numProcs; ++proc) {
3286               PetscInt dof, off, pPart;
3287 
3288               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3289               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3290               for (pPart = off; pPart < off+dof; ++pPart) {
3291                 if (partArray[pPart] == point) {
3292                   ++stratumSizes[proc*next->numStrata+s];
3293                   break;
3294                 }
3295               }
3296             }
3297           }
3298         }
3299         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3300       }
3301       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3302       /* Calculate stratumOffsets */
3303       newLabel->stratumOffsets[0] = 0;
3304       for (s = 0; s < newLabel->numStrata; ++s) {
3305         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3306       }
3307       /* Pack points and Scatter */
3308       if (!rank) {
3309         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3310         displs[0] = 0;
3311         for (p = 0; p < numProcs; ++p) {
3312           sendcnts[p] = 0;
3313           for (s = 0; s < next->numStrata; ++s) {
3314             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3315           }
3316           offsets[p]  = displs[p];
3317           displs[p+1] = displs[p] + sendcnts[p];
3318         }
3319         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3320         for (s = 0; s < next->numStrata; ++s) {
3321           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3322             const PetscInt point = next->points[p];
3323             PetscInt       proc;
3324 
3325             for (proc = 0; proc < numProcs; ++proc) {
3326               PetscInt dof, off, pPart;
3327 
3328               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3329               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3330               for (pPart = off; pPart < off+dof; ++pPart) {
3331                 if (partArray[pPart] == point) {
3332                   points[offsets[proc]++] = point;
3333                   break;
3334                 }
3335               }
3336             }
3337           }
3338         }
3339       }
3340       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3341       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3342       ierr = PetscFree(points);CHKERRQ(ierr);
3343       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3344       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3345       /* Renumber points */
3346       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3347       /* Sort points */
3348       for (s = 0; s < newLabel->numStrata; ++s) {
3349         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3350       }
3351       /* Insert into list */
3352       if (newNext) {
3353         newNext->next = newLabel;
3354       } else {
3355         pmesh->labels = newLabel;
3356       }
3357       newNext = newLabel;
3358       if (!rank) {next = next->next;}
3359     }
3360   }
3361   /* Cleanup Partition */
3362   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3363   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3364   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3365   ierr = ISDestroy(&part);CHKERRQ(ierr);
3366   /* Create point SF for parallel mesh */
3367   {
3368     const PetscInt *leaves;
3369     PetscSFNode    *remotePoints, *rowners, *lowners;
3370     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3371     PetscInt        pStart, pEnd;
3372 
3373     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3374     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3375     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3376     for (p=0; p<numRoots; p++) {
3377       rowners[p].rank = -1;
3378       rowners[p].index = -1;
3379     }
3380     if (origCellPart) {
3381       /* Make sure cells in the original partition are not assigned to other procs */
3382       const PetscInt *origCells;
3383 
3384       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3385       for (p = 0; p < numProcs; ++p) {
3386         PetscInt dof, off, d;
3387 
3388         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3389         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3390         for(d = off; d < off+dof; ++d) {
3391           rowners[origCells[d]].rank = p;
3392         }
3393       }
3394       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3395     }
3396     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3397     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3398 
3399     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3400     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3401     for (p = 0; p < numLeaves; ++p) {
3402       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3403         lowners[p].rank = rank;
3404         lowners[p].index = leaves ? leaves[p] : p;
3405       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3406         lowners[p].rank = -2;
3407         lowners[p].index = -2;
3408       }
3409     }
3410     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3411       rowners[p].rank = -3;
3412       rowners[p].index = -3;
3413     }
3414     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3415     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3416     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3417     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3418     for (p = 0; p < numLeaves; ++p) {
3419       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3420       if (lowners[p].rank != rank) ++numGhostPoints;
3421     }
3422     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3423     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3424     for (p = 0, gp = 0; p < numLeaves; ++p) {
3425       if (lowners[p].rank != rank) {
3426         ghostPoints[gp]       = leaves ? leaves[p] : p;
3427         remotePoints[gp].rank  = lowners[p].rank;
3428         remotePoints[gp].index = lowners[p].index;
3429         ++gp;
3430       }
3431     }
3432     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3433     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3434     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3435   }
3436   /* Cleanup */
3437   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3438   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3439   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3440   PetscFunctionReturn(0);
3441 }
3442 
3443 #undef __FUNCT__
3444 #define __FUNCT__ "DMPlexRenumber_Private"
3445 /*
3446   Reasons to renumber:
3447 
3448   1) Permute points, e.g. bandwidth reduction (Renumber)
3449 
3450     a) Must not mix strata
3451 
3452   2) Shift numbers for point insertion (Shift)
3453 
3454     a) Want operation brken into parts so that insertion can be interleaved
3455 
3456   renumbering - An IS which provides the new numbering
3457 */
3458 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3459 {
3460   PetscFunctionBegin;
3461   PetscFunctionReturn(0);
3462 }
3463 
3464 #undef __FUNCT__
3465 #define __FUNCT__ "DMPlexShiftPoint_Private"
3466 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3467 {
3468   if (depth < 0) return p;
3469   /* Cells    */ if (p < depthEnd[depth])   return p;
3470   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3471   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3472   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3473 }
3474 
3475 #undef __FUNCT__
3476 #define __FUNCT__ "DMPlexShiftSizes_Private"
3477 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3478 {
3479   PetscInt      *depthEnd;
3480   PetscInt       depth = 0, d, pStart, pEnd, p;
3481   PetscErrorCode ierr;
3482 
3483   PetscFunctionBegin;
3484   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3485   if (depth < 0) PetscFunctionReturn(0);
3486   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3487   /* Step 1: Expand chart */
3488   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3489   for(d = 0; d <= depth; ++d) {
3490     pEnd += depthShift[d];
3491     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3492   }
3493   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3494   /* Step 2: Set cone and support sizes */
3495   for(d = 0; d <= depth; ++d) {
3496     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3497     for(p = pStart; p < pEnd; ++p) {
3498       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3499       PetscInt size;
3500 
3501       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3502       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3503       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3504       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3505     }
3506   }
3507   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3508   PetscFunctionReturn(0);
3509 }
3510 
3511 #undef __FUNCT__
3512 #define __FUNCT__ "DMPlexShiftPoints_Private"
3513 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3514 {
3515   PetscInt      *depthEnd, *newpoints;
3516   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3517   PetscErrorCode ierr;
3518 
3519   PetscFunctionBegin;
3520   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3521   if (depth < 0) PetscFunctionReturn(0);
3522   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3523   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3524   for(d = 0; d <= depth; ++d) {
3525     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3526   }
3527   /* Step 5: Set cones and supports */
3528   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3529   for(p = pStart; p < pEnd; ++p) {
3530     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3531     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3532 
3533     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3534     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3535     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3536     for(i = 0; i < size; ++i) {
3537       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3538     }
3539     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3540     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3541     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3542     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3543     for(i = 0; i < size; ++i) {
3544       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3545     }
3546     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3547   }
3548   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3549   PetscFunctionReturn(0);
3550 }
3551 
3552 #undef __FUNCT__
3553 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3554 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3555 {
3556   PetscSection   coordSection, newCoordSection;
3557   Vec            coordinates;
3558   PetscInt      *depthEnd;
3559   PetscInt       dim, depth = 0, d, vStart, vEnd, v;
3560   PetscErrorCode ierr;
3561 
3562   PetscFunctionBegin;
3563   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3564   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3565   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3566   for(d = 0; d <= depth; ++d) {
3567     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3568   }
3569   /* Step 8: Convert coordinates */
3570   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3571   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3572   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3573   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3574   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3575   ierr = PetscSectionSetChart(newCoordSection, DMPlexShiftPoint_Private(vStart, depth, depthEnd, depthShift), DMPlexShiftPoint_Private(vEnd, depth, depthEnd, depthShift));CHKERRQ(ierr);
3576   for(v = vStart; v < vEnd; ++v) {
3577     const PetscInt newv = DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift);
3578     ierr = PetscSectionSetDof(newCoordSection, newv, dim);CHKERRQ(ierr);
3579     ierr = PetscSectionSetFieldDof(newCoordSection, newv, 0, dim);CHKERRQ(ierr);
3580   }
3581   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3582   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3583   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3584   ierr = DMSetCoordinatesLocal(dmNew, coordinates);CHKERRQ(ierr);
3585   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3586   PetscFunctionReturn(0);
3587 }
3588 
3589 #undef __FUNCT__
3590 #define __FUNCT__ "DMPlexShiftSF_Private"
3591 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3592 {
3593   PetscInt          *depthEnd;
3594   PetscInt           depth = 0, d;
3595   PetscSF            sfPoint, sfPointNew;
3596   const PetscSFNode *remotePoints;
3597   PetscSFNode       *gremotePoints;
3598   const PetscInt    *localPoints;
3599   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3600   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3601   PetscMPIInt        numProcs;
3602   PetscErrorCode     ierr;
3603 
3604   PetscFunctionBegin;
3605   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3606   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3607   for(d = 0; d <= depth; ++d) {
3608     totShift += depthShift[d];
3609     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3610   }
3611   /* Step 9: Convert pointSF */
3612   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3613   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3614   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3615   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3616   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3617   if (numRoots >= 0) {
3618     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3619     for(l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3620     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3621     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3622     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3623     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3624     for(l = 0; l < numLeaves; ++l) {
3625       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3626       gremotePoints[l].rank  = remotePoints[l].rank;
3627       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3628     }
3629     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3630     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3631   }
3632   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3633   PetscFunctionReturn(0);
3634 }
3635 
3636 #undef __FUNCT__
3637 #define __FUNCT__ "DMPlexShiftLabels_Private"
3638 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3639 {
3640   PetscSF        sfPoint;
3641   DMLabel        vtkLabel, ghostLabel;
3642   PetscInt      *depthEnd;
3643   const PetscSFNode *leafRemote;
3644   const PetscInt    *leafLocal;
3645   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3646   PetscMPIInt    rank;
3647   PetscErrorCode ierr;
3648 
3649   PetscFunctionBegin;
3650   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3651   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3652   for(d = 0; d <= depth; ++d) {
3653     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3654   }
3655   /* Step 10: Convert labels */
3656   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3657   for(l = 0; l < numLabels; ++l) {
3658     DMLabel         label, newlabel;
3659     const char     *lname;
3660     PetscBool       isDepth;
3661     IS              valueIS;
3662     const PetscInt *values;
3663     PetscInt        numValues, val;
3664 
3665     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3666     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3667     if (isDepth) continue;
3668     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3669     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3670     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3671     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3672     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3673     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3674     for(val = 0; val < numValues; ++val) {
3675       IS              pointIS;
3676       const PetscInt *points;
3677       PetscInt        numPoints, p;
3678 
3679       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3680       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3681       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3682       for(p = 0; p < numPoints; ++p) {
3683         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3684 
3685         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3686       }
3687       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3688       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3689     }
3690     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3691     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3692   }
3693   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3694   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3695   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3696   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3697   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3698   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3699   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3700   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3701   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3702   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3703   for(l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3704     for(; c < leafLocal[l] && c < cEnd; ++c) {
3705       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3706     }
3707     if (leafLocal[l] >= cEnd) break;
3708     if (leafRemote[l].rank == rank) {
3709       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3710     } else {
3711       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3712     }
3713   }
3714   for(; c < cEnd; ++c) {
3715     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3716   }
3717   if (0) {
3718     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3719     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3720     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3721   }
3722   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3723   for(f = fStart; f < fEnd; ++f) {
3724     PetscInt numCells;
3725 
3726     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3727     if (numCells < 2) {
3728       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3729     } else {
3730       const PetscInt *cells = PETSC_NULL;
3731       PetscInt        vA, vB;
3732 
3733       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3734       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3735       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3736       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3737     }
3738   }
3739   if (0) {
3740     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3741     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3742     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3743   }
3744   PetscFunctionReturn(0);
3745 }
3746 
3747 #undef __FUNCT__
3748 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3749 /*@C
3750   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3751 
3752   Collective on dm
3753 
3754   Input Parameters:
3755 + dm - The original DM
3756 - labelName - The label specifying the boundary faces (this could be auto-generated)
3757 
3758   Output Parameters:
3759 + numGhostCells - The number of ghost cells added to the DM
3760 - dmGhosted - The new DM
3761 
3762   Level: developer
3763 
3764 .seealso: DMCreate()
3765 */
3766 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3767 {
3768   DMLabel         label;
3769   IS              valueIS;
3770   const PetscInt *values;
3771   PetscInt       *depthShift;
3772   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3773   PetscErrorCode  ierr;
3774 
3775   PetscFunctionBegin;
3776   /* Count ghost cells */
3777   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3778   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3779   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3780   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3781   *numGhostCells = 0;
3782   for(fs = 0; fs < numFS; ++fs) {
3783     PetscInt numBdFaces;
3784 
3785     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3786     *numGhostCells += numBdFaces;
3787   }
3788   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3789   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3790   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3791   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3792   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3793   /* Step 3: Set cone/support sizes for new points */
3794   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3795   for(c = cEnd; c < cEnd + *numGhostCells; ++c) {
3796     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3797   }
3798   for(fs = 0; fs < numFS; ++fs) {
3799     IS              faceIS;
3800     const PetscInt *faces;
3801     PetscInt        numFaces, f;
3802 
3803     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3804     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3805     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3806     for(f = 0; f < numFaces; ++f) {
3807       PetscInt size;
3808 
3809       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3810       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3811       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3812     }
3813     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3814     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3815   }
3816   /* Step 4: Setup ghosted DM */
3817   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3818   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3819   /* Step 6: Set cones and supports for new points */
3820   ghostCell = cEnd;
3821   for(fs = 0; fs < numFS; ++fs) {
3822     IS              faceIS;
3823     const PetscInt *faces;
3824     PetscInt        numFaces, f;
3825 
3826     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3827     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3828     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3829     for(f = 0; f < numFaces; ++f, ++ghostCell) {
3830       PetscInt newFace = faces[f] + *numGhostCells;
3831 
3832       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3833       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3834     }
3835     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3836     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3837   }
3838   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3839   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3840   /* Step 7: Stratify */
3841   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3842   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3843   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3844   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3845   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3846   PetscFunctionReturn(0);
3847 }
3848 
3849 #undef __FUNCT__
3850 #define __FUNCT__ "DMPlexConstructGhostCells"
3851 /*@C
3852   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3853 
3854   Collective on dm
3855 
3856   Input Parameters:
3857 + dm - The original DM
3858 - labelName - The label specifying the boundary faces (this could be auto-generated)
3859 
3860   Output Parameters:
3861 + numGhostCells - The number of ghost cells added to the DM
3862 - dmGhosted - The new DM
3863 
3864   Level: developer
3865 
3866 .seealso: DMCreate()
3867 */
3868 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3869 {
3870   DM             gdm;
3871   PetscInt       dim;
3872   PetscErrorCode ierr;
3873 
3874   PetscFunctionBegin;
3875   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3876   PetscValidPointer(numGhostCells, 3);
3877   PetscValidPointer(dmGhosted, 4);
3878   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3879   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3880   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3881   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3882   switch(dim) {
3883   case 2:
3884     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3885     break;
3886   default:
3887     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3888   }
3889   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3890   *dmGhosted = gdm;
3891   PetscFunctionReturn(0);
3892 }
3893 
3894 #undef __FUNCT__
3895 #define __FUNCT__ "DMPlexInterpolate_2D"
3896 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
3897 {
3898   DM             idm;
3899   DM_Plex    *mesh;
3900   PetscHashIJ    edgeTable;
3901   PetscInt      *off;
3902   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
3903   PetscInt       numEdges, firstEdge, edge, e;
3904   PetscErrorCode ierr;
3905 
3906   PetscFunctionBegin;
3907   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3908   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3909   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3910   numCells    = cEnd - cStart;
3911   numVertices = vEnd - vStart;
3912   firstEdge   = numCells + numVertices;
3913   numEdges    = 0 ;
3914   /* Count edges using algorithm from CreateNeighborCSR */
3915   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
3916   if (off) {
3917     PetscInt numCorners = 0;
3918 
3919     numEdges = off[numCells]/2;
3920 #if 0
3921     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
3922     numEdges += 3*numCells - off[numCells];
3923 #else
3924     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
3925     for(c = cStart; c < cEnd; ++c) {
3926       PetscInt coneSize;
3927 
3928       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
3929       numCorners += coneSize;
3930     }
3931     numEdges += numCorners - off[numCells];
3932 #endif
3933   }
3934 #if 0
3935   /* Check Euler characteristic V - E + F = 1 */
3936   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
3937 #endif
3938   /* Create interpolated mesh */
3939   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
3940   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
3941   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
3942   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
3943   for (c = 0; c < numCells; ++c) {
3944     PetscInt numCorners;
3945 
3946     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
3947     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
3948   }
3949   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
3950     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
3951   }
3952   ierr = DMSetUp(idm);CHKERRQ(ierr);
3953   /* Get edge cones from subsets of cell vertices */
3954   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
3955   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
3956 
3957   for (c = 0, edge = firstEdge; c < numCells; ++c) {
3958     const PetscInt *cellFaces;
3959     PetscInt        numCellFaces, faceSize, cf;
3960 
3961     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
3962     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
3963     for (cf = 0; cf < numCellFaces; ++cf) {
3964 #if 1
3965       PetscHashIJKey key = {PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]),
3966                             PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1])};
3967 
3968       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
3969       if (e < 0) {
3970         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
3971         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
3972         e    = edge++;
3973       }
3974 #else
3975       PetscBool found = PETSC_FALSE;
3976 
3977       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
3978       for (e = firstEdge; e < edge; ++e) {
3979         const PetscInt *cone;
3980 
3981         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
3982         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
3983             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
3984           found = PETSC_TRUE;
3985           break;
3986         }
3987       }
3988       if (!found) {
3989         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
3990         ++edge;
3991       }
3992 #endif
3993       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
3994     }
3995   }
3996   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
3997   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
3998   ierr = PetscFree(off);CHKERRQ(ierr);
3999   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4000   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4001   mesh = (DM_Plex *) (idm)->data;
4002   /* Orient edges */
4003   for (c = 0; c < numCells; ++c) {
4004     const PetscInt *cone = PETSC_NULL, *cellFaces;
4005     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4006 
4007     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4008     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4009     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4010     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4011     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4012     for (cf = 0; cf < numCellFaces; ++cf) {
4013       const PetscInt *econe = PETSC_NULL;
4014       PetscInt        esize;
4015 
4016       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4017       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4018       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]);
4019       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4020         /* Correctly oriented */
4021         mesh->coneOrientations[coff+cf] = 0;
4022       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4023         /* Start at index 1, and reverse orientation */
4024         mesh->coneOrientations[coff+cf] = -(1+1);
4025       }
4026     }
4027   }
4028   *dmInt  = idm;
4029   PetscFunctionReturn(0);
4030 }
4031 
4032 #undef __FUNCT__
4033 #define __FUNCT__ "DMPlexInterpolate_3D"
4034 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4035 {
4036   DM             idm, fdm;
4037   DM_Plex    *mesh;
4038   PetscInt      *off;
4039   const PetscInt numCorners = 4;
4040   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4041   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4042   PetscErrorCode ierr;
4043 
4044   PetscFunctionBegin;
4045   {
4046     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4047     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4048     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4049   }
4050   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4051   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4052   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4053   numCells    = cEnd - cStart;
4054   numVertices = vEnd - vStart;
4055   firstFace   = numCells + numVertices;
4056   numFaces    = 0 ;
4057   /* Count faces using algorithm from CreateNeighborCSR */
4058   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4059   if (off) {
4060     numFaces = off[numCells]/2;
4061     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4062     numFaces += 4*numCells - off[numCells];
4063   }
4064   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4065   firstEdge = firstFace + numFaces;
4066   numEdges  = numVertices + numFaces - numCells - 1;
4067   /* Create interpolated mesh */
4068   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4069   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4070   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4071   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4072   for (c = 0; c < numCells; ++c) {
4073     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4074   }
4075   for (f = firstFace; f < firstFace+numFaces; ++f) {
4076     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4077   }
4078   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4079     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4080   }
4081   ierr = DMSetUp(idm);CHKERRQ(ierr);
4082   /* Get face cones from subsets of cell vertices */
4083   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4084   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4085   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4086   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4087   for (f = firstFace; f < firstFace+numFaces; ++f) {
4088     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4089   }
4090   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4091   for (c = 0, face = firstFace; c < numCells; ++c) {
4092     const PetscInt *cellFaces;
4093     PetscInt        numCellFaces, faceSize, cf;
4094 
4095     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4096     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4097     for (cf = 0; cf < numCellFaces; ++cf) {
4098       PetscBool found = PETSC_FALSE;
4099 
4100       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4101       for (f = firstFace; f < face; ++f) {
4102         const PetscInt *cone = PETSC_NULL;
4103 
4104         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4105         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4106             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4107             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4108             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4109             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4110             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4111           found = PETSC_TRUE;
4112           break;
4113         }
4114       }
4115       if (!found) {
4116         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4117         /* Save the vertices for orientation calculation */
4118         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4119         ++face;
4120       }
4121       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4122     }
4123   }
4124   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4125   /* Get edge cones from subsets of face vertices */
4126   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4127     const PetscInt *cellFaces;
4128     PetscInt        numCellFaces, faceSize, cf;
4129 
4130     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4131     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4132     for (cf = 0; cf < numCellFaces; ++cf) {
4133       PetscBool found = PETSC_FALSE;
4134 
4135       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4136       for (e = firstEdge; e < edge; ++e) {
4137         const PetscInt *cone = PETSC_NULL;
4138 
4139         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4140         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4141             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4142           found = PETSC_TRUE;
4143           break;
4144         }
4145       }
4146       if (!found) {
4147         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4148         ++edge;
4149       }
4150       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4151     }
4152   }
4153   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4154   ierr = PetscFree(off);CHKERRQ(ierr);
4155   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4156   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4157   mesh = (DM_Plex *) (idm)->data;
4158   /* Orient edges */
4159   for (f = firstFace; f < firstFace+numFaces; ++f) {
4160     const PetscInt *cone, *cellFaces;
4161     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4162 
4163     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4164     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4165     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4166     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4167     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4168     for (cf = 0; cf < numCellFaces; ++cf) {
4169       const PetscInt *econe;
4170       PetscInt        esize;
4171 
4172       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4173       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4174       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]);
4175       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4176         /* Correctly oriented */
4177         mesh->coneOrientations[coff+cf] = 0;
4178       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4179         /* Start at index 1, and reverse orientation */
4180         mesh->coneOrientations[coff+cf] = -(1+1);
4181       }
4182     }
4183   }
4184   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4185   /* Orient faces */
4186   for (c = 0; c < numCells; ++c) {
4187     const PetscInt *cone, *cellFaces;
4188     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4189 
4190     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4191     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4192     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4193     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4194     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4195     for (cf = 0; cf < numCellFaces; ++cf) {
4196       PetscInt *origClosure = PETSC_NULL, *closure;
4197       PetscInt  closureSize, i;
4198 
4199       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4200       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4201       for (i = 4; i < 7; ++i) {
4202         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);
4203       }
4204       closure = &origClosure[4*2];
4205       /* Remember that this is the orientation for edges, not vertices */
4206       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4207         /* Correctly oriented */
4208         mesh->coneOrientations[coff+cf] = 0;
4209       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4210         /* Shifted by 1 */
4211         mesh->coneOrientations[coff+cf] = 1;
4212       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4213         /* Shifted by 2 */
4214         mesh->coneOrientations[coff+cf] = 2;
4215       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4216         /* Start at edge 1, and reverse orientation */
4217         mesh->coneOrientations[coff+cf] = -(1+1);
4218       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4219         /* Start at index 0, and reverse orientation */
4220         mesh->coneOrientations[coff+cf] = -(0+1);
4221       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4222         /* Start at index 2, and reverse orientation */
4223         mesh->coneOrientations[coff+cf] = -(2+1);
4224       } 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);
4225       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4226     }
4227   }
4228   {
4229     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4230     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4231     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4232   }
4233   *dmInt  = idm;
4234   PetscFunctionReturn(0);
4235 }
4236 
4237 #undef __FUNCT__
4238 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4239 /*
4240   This takes as input the common mesh generator output, a list of the vertices for each cell
4241 */
4242 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4243 {
4244   PetscInt      *cone, c, p;
4245   PetscErrorCode ierr;
4246 
4247   PetscFunctionBegin;
4248   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4249   for (c = 0; c < numCells; ++c) {
4250     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4251   }
4252   ierr = DMSetUp(dm);CHKERRQ(ierr);
4253   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4254   for (c = 0; c < numCells; ++c) {
4255     for (p = 0; p < numCorners; ++p) {
4256       cone[p] = cells[c*numCorners+p]+numCells;
4257     }
4258     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4259   }
4260   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4261   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4262   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4263   PetscFunctionReturn(0);
4264 }
4265 
4266 #undef __FUNCT__
4267 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4268 /*
4269   This takes as input the coordinates for each vertex
4270 */
4271 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4272 {
4273   PetscSection   coordSection;
4274   Vec            coordinates;
4275   PetscScalar   *coords;
4276   PetscInt       coordSize, v, d;
4277   PetscErrorCode ierr;
4278 
4279   PetscFunctionBegin;
4280   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4281   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4282   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4283   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4284   for (v = numCells; v < numCells+numVertices; ++v) {
4285     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4286     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4287   }
4288   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4289   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4290   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4291   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4292   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4293   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4294   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4295   for (v = 0; v < numVertices; ++v) {
4296     for (d = 0; d < spaceDim; ++d) {
4297       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4298     }
4299   }
4300   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4301   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4302   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4303   PetscFunctionReturn(0);
4304 }
4305 
4306 #undef __FUNCT__
4307 #define __FUNCT__ "DMPlexCreateFromCellList"
4308 /*
4309   This takes as input the common mesh generator output, a list of the vertices for each cell
4310 */
4311 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4312 {
4313   PetscErrorCode ierr;
4314 
4315   PetscFunctionBegin;
4316   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4317   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4318   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4319   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4320   if (interpolate) {
4321     DM idm;
4322 
4323     switch(dim) {
4324     case 2:
4325       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4326     case 3:
4327       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4328     default:
4329       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4330     }
4331     ierr = DMDestroy(dm);CHKERRQ(ierr);
4332     *dm  = idm;
4333   }
4334   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4335   PetscFunctionReturn(0);
4336 }
4337 
4338 #ifdef PETSC_HAVE_TRIANGLE
4339 #include <triangle.h>
4340 
4341 #undef __FUNCT__
4342 #define __FUNCT__ "InitInput_Triangle"
4343 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4344 {
4345   PetscFunctionBegin;
4346   inputCtx->numberofpoints = 0;
4347   inputCtx->numberofpointattributes = 0;
4348   inputCtx->pointlist = PETSC_NULL;
4349   inputCtx->pointattributelist = PETSC_NULL;
4350   inputCtx->pointmarkerlist = PETSC_NULL;
4351   inputCtx->numberofsegments = 0;
4352   inputCtx->segmentlist = PETSC_NULL;
4353   inputCtx->segmentmarkerlist = PETSC_NULL;
4354   inputCtx->numberoftriangleattributes = 0;
4355   inputCtx->trianglelist = PETSC_NULL;
4356   inputCtx->numberofholes = 0;
4357   inputCtx->holelist = PETSC_NULL;
4358   inputCtx->numberofregions = 0;
4359   inputCtx->regionlist = PETSC_NULL;
4360   PetscFunctionReturn(0);
4361 }
4362 
4363 #undef __FUNCT__
4364 #define __FUNCT__ "InitOutput_Triangle"
4365 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4366 {
4367   PetscFunctionBegin;
4368   outputCtx->numberofpoints = 0;
4369   outputCtx->pointlist = PETSC_NULL;
4370   outputCtx->pointattributelist = PETSC_NULL;
4371   outputCtx->pointmarkerlist = PETSC_NULL;
4372   outputCtx->numberoftriangles = 0;
4373   outputCtx->trianglelist = PETSC_NULL;
4374   outputCtx->triangleattributelist = PETSC_NULL;
4375   outputCtx->neighborlist = PETSC_NULL;
4376   outputCtx->segmentlist = PETSC_NULL;
4377   outputCtx->segmentmarkerlist = PETSC_NULL;
4378   outputCtx->numberofedges = 0;
4379   outputCtx->edgelist = PETSC_NULL;
4380   outputCtx->edgemarkerlist = PETSC_NULL;
4381   PetscFunctionReturn(0);
4382 }
4383 
4384 #undef __FUNCT__
4385 #define __FUNCT__ "FiniOutput_Triangle"
4386 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4387 {
4388   PetscFunctionBegin;
4389   free(outputCtx->pointmarkerlist);
4390   free(outputCtx->edgelist);
4391   free(outputCtx->edgemarkerlist);
4392   free(outputCtx->trianglelist);
4393   free(outputCtx->neighborlist);
4394   PetscFunctionReturn(0);
4395 }
4396 
4397 #undef __FUNCT__
4398 #define __FUNCT__ "DMPlexGenerate_Triangle"
4399 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4400 {
4401   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4402   PetscInt             dim              = 2;
4403   const PetscBool      createConvexHull = PETSC_FALSE;
4404   const PetscBool      constrained      = PETSC_FALSE;
4405   struct triangulateio in;
4406   struct triangulateio out;
4407   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4408   PetscMPIInt          rank;
4409   PetscErrorCode       ierr;
4410 
4411   PetscFunctionBegin;
4412   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4413   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4414   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4415   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4416   in.numberofpoints = vEnd - vStart;
4417   if (in.numberofpoints > 0) {
4418     PetscSection coordSection;
4419     Vec          coordinates;
4420     PetscScalar *array;
4421 
4422     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4423     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4424     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4425     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4426     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4427     for (v = vStart; v < vEnd; ++v) {
4428       const PetscInt idx = v - vStart;
4429       PetscInt       off, d;
4430 
4431       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4432       for (d = 0; d < dim; ++d) {
4433         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4434       }
4435       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4436     }
4437     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4438   }
4439   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4440   in.numberofsegments = eEnd - eStart;
4441   if (in.numberofsegments > 0) {
4442     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4443     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4444     for (e = eStart; e < eEnd; ++e) {
4445       const PetscInt  idx = e - eStart;
4446       const PetscInt *cone;
4447 
4448       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4449       in.segmentlist[idx*2+0] = cone[0] - vStart;
4450       in.segmentlist[idx*2+1] = cone[1] - vStart;
4451       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4452     }
4453   }
4454 #if 0 /* Do not currently support holes */
4455   PetscReal *holeCoords;
4456   PetscInt   h, d;
4457 
4458   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4459   if (in.numberofholes > 0) {
4460     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4461     for (h = 0; h < in.numberofholes; ++h) {
4462       for (d = 0; d < dim; ++d) {
4463         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4464       }
4465     }
4466   }
4467 #endif
4468   if (!rank) {
4469     char args[32];
4470 
4471     /* Take away 'Q' for verbose output */
4472     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4473     if (createConvexHull) {
4474       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4475     }
4476     if (constrained) {
4477       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4478     }
4479     triangulate(args, &in, &out, PETSC_NULL);
4480   }
4481   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4482   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4483   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4484   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4485   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4486 
4487   {
4488     const PetscInt numCorners  = 3;
4489     const PetscInt numCells    = out.numberoftriangles;
4490     const PetscInt numVertices = out.numberofpoints;
4491     const int     *cells       = out.trianglelist;
4492     const double  *meshCoords  = out.pointlist;
4493 
4494     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4495     /* Set labels */
4496     for (v = 0; v < numVertices; ++v) {
4497       if (out.pointmarkerlist[v]) {
4498         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4499       }
4500     }
4501     if (interpolate) {
4502       for (e = 0; e < out.numberofedges; e++) {
4503         if (out.edgemarkerlist[e]) {
4504           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4505           const PetscInt *edges;
4506           PetscInt        numEdges;
4507 
4508           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4509           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4510           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4511           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4512         }
4513       }
4514     }
4515     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4516   }
4517 #if 0 /* Do not currently support holes */
4518   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4519 #endif
4520   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4521   PetscFunctionReturn(0);
4522 }
4523 
4524 #undef __FUNCT__
4525 #define __FUNCT__ "DMPlexRefine_Triangle"
4526 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4527 {
4528   MPI_Comm             comm = ((PetscObject) dm)->comm;
4529   PetscInt             dim  = 2;
4530   struct triangulateio in;
4531   struct triangulateio out;
4532   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4533   PetscMPIInt          rank;
4534   PetscErrorCode       ierr;
4535 
4536   PetscFunctionBegin;
4537   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4538   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4539   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4540   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4541   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4542   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4543   in.numberofpoints = vEnd - vStart;
4544   if (in.numberofpoints > 0) {
4545     PetscSection coordSection;
4546     Vec          coordinates;
4547     PetscScalar *array;
4548 
4549     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4550     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4551     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4552     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4553     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4554     for (v = vStart; v < vEnd; ++v) {
4555       const PetscInt idx = v - vStart;
4556       PetscInt       off, d;
4557 
4558       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4559       for (d = 0; d < dim; ++d) {
4560         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4561       }
4562       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4563     }
4564     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4565   }
4566   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4567   in.numberofcorners   = 3;
4568   in.numberoftriangles = cEnd - cStart;
4569   in.trianglearealist  = (double *) maxVolumes;
4570   if (in.numberoftriangles > 0) {
4571     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4572     for (c = cStart; c < cEnd; ++c) {
4573       const PetscInt idx     = c - cStart;
4574       PetscInt      *closure = PETSC_NULL;
4575       PetscInt       closureSize;
4576 
4577       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4578       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4579       for (v = 0; v < 3; ++v) {
4580         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4581       }
4582       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4583     }
4584   }
4585   /* TODO: Segment markers are missing on input */
4586 #if 0 /* Do not currently support holes */
4587   PetscReal *holeCoords;
4588   PetscInt   h, d;
4589 
4590   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4591   if (in.numberofholes > 0) {
4592     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4593     for (h = 0; h < in.numberofholes; ++h) {
4594       for (d = 0; d < dim; ++d) {
4595         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4596       }
4597     }
4598   }
4599 #endif
4600   if (!rank) {
4601     char args[32];
4602 
4603     /* Take away 'Q' for verbose output */
4604     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4605     triangulate(args, &in, &out, PETSC_NULL);
4606   }
4607   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4608   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4609   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4610   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4611   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4612 
4613   {
4614     const PetscInt numCorners  = 3;
4615     const PetscInt numCells    = out.numberoftriangles;
4616     const PetscInt numVertices = out.numberofpoints;
4617     const int     *cells       = out.trianglelist;
4618     const double  *meshCoords  = out.pointlist;
4619     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4620 
4621     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4622     /* Set labels */
4623     for (v = 0; v < numVertices; ++v) {
4624       if (out.pointmarkerlist[v]) {
4625         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4626       }
4627     }
4628     if (interpolate) {
4629       PetscInt e;
4630 
4631       for (e = 0; e < out.numberofedges; e++) {
4632         if (out.edgemarkerlist[e]) {
4633           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4634           const PetscInt *edges;
4635           PetscInt        numEdges;
4636 
4637           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4638           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4639           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4640           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4641         }
4642       }
4643     }
4644     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4645   }
4646 #if 0 /* Do not currently support holes */
4647   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4648 #endif
4649   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4650   PetscFunctionReturn(0);
4651 }
4652 #endif
4653 
4654 #ifdef PETSC_HAVE_TETGEN
4655 #include <tetgen.h>
4656 #undef __FUNCT__
4657 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4658 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4659 {
4660   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4661   const PetscInt dim  = 3;
4662   ::tetgenio     in;
4663   ::tetgenio     out;
4664   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4665   PetscMPIInt    rank;
4666   PetscErrorCode ierr;
4667 
4668   PetscFunctionBegin;
4669   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4670   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4671   in.numberofpoints = vEnd - vStart;
4672   if (in.numberofpoints > 0) {
4673     PetscSection coordSection;
4674     Vec          coordinates;
4675     PetscScalar *array;
4676 
4677     in.pointlist       = new double[in.numberofpoints*dim];
4678     in.pointmarkerlist = new int[in.numberofpoints];
4679     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4680     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4681     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4682     for (v = vStart; v < vEnd; ++v) {
4683       const PetscInt idx = v - vStart;
4684       PetscInt       off, d;
4685 
4686       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4687       for (d = 0; d < dim; ++d) {
4688         in.pointlist[idx*dim + d] = array[off+d];
4689       }
4690       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4691     }
4692     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4693   }
4694   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4695   in.numberoffacets = fEnd - fStart;
4696   if (in.numberoffacets > 0) {
4697     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4698     in.facetmarkerlist = new int[in.numberoffacets];
4699     for (f = fStart; f < fEnd; ++f) {
4700       const PetscInt idx    = f - fStart;
4701       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
4702 
4703       in.facetlist[idx].numberofpolygons = 1;
4704       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4705       in.facetlist[idx].numberofholes    = 0;
4706       in.facetlist[idx].holelist         = NULL;
4707 
4708       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4709       for (p = 0; p < numPoints*2; p += 2) {
4710         const PetscInt point = points[p];
4711         if ((point >= vStart) && (point < vEnd)) {
4712           points[numVertices++] = point;
4713         }
4714       }
4715 
4716       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4717       poly->numberofvertices = numVertices;
4718       poly->vertexlist       = new int[poly->numberofvertices];
4719       for (v = 0; v < numVertices; ++v) {
4720         const PetscInt vIdx = points[v] - vStart;
4721         poly->vertexlist[v] = vIdx;
4722       }
4723       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4724       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4725     }
4726   }
4727   if (!rank) {
4728     char args[32];
4729 
4730     /* Take away 'Q' for verbose output */
4731     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4732     ::tetrahedralize(args, &in, &out);
4733   }
4734   {
4735     const PetscInt numCorners  = 4;
4736     const PetscInt numCells    = out.numberoftetrahedra;
4737     const PetscInt numVertices = out.numberofpoints;
4738     const int     *cells       = out.tetrahedronlist;
4739     const double  *meshCoords  = out.pointlist;
4740 
4741     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4742     /* Set labels */
4743     for (v = 0; v < numVertices; ++v) {
4744       if (out.pointmarkerlist[v]) {
4745         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4746       }
4747     }
4748     if (interpolate) {
4749       PetscInt e;
4750 
4751       for (e = 0; e < out.numberofedges; e++) {
4752         if (out.edgemarkerlist[e]) {
4753           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4754           const PetscInt *edges;
4755           PetscInt        numEdges;
4756 
4757           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4758           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4759           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4760           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4761         }
4762       }
4763       for (f = 0; f < out.numberoftrifaces; f++) {
4764         if (out.trifacemarkerlist[f]) {
4765           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4766           const PetscInt *faces;
4767           PetscInt        numFaces;
4768 
4769           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4770           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4771           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4772           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4773         }
4774       }
4775     }
4776     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4777   }
4778   PetscFunctionReturn(0);
4779 }
4780 
4781 #undef __FUNCT__
4782 #define __FUNCT__ "DMPlexRefine_Tetgen"
4783 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4784 {
4785   MPI_Comm       comm = ((PetscObject) dm)->comm;
4786   const PetscInt dim  = 3;
4787   ::tetgenio     in;
4788   ::tetgenio     out;
4789   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4790   PetscMPIInt    rank;
4791   PetscErrorCode ierr;
4792 
4793   PetscFunctionBegin;
4794   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4795   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4796   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4797   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4798   in.numberofpoints = vEnd - vStart;
4799   if (in.numberofpoints > 0) {
4800     PetscSection coordSection;
4801     Vec          coordinates;
4802     PetscScalar *array;
4803 
4804     in.pointlist       = new double[in.numberofpoints*dim];
4805     in.pointmarkerlist = new int[in.numberofpoints];
4806     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4807     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4808     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4809     for (v = vStart; v < vEnd; ++v) {
4810       const PetscInt idx = v - vStart;
4811       PetscInt       off, d;
4812 
4813       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4814       for (d = 0; d < dim; ++d) {
4815         in.pointlist[idx*dim + d] = array[off+d];
4816       }
4817       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4818     }
4819     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4820   }
4821   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4822   in.numberofcorners       = 4;
4823   in.numberoftetrahedra    = cEnd - cStart;
4824   in.tetrahedronvolumelist = (double *) maxVolumes;
4825   if (in.numberoftetrahedra > 0) {
4826     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
4827     for (c = cStart; c < cEnd; ++c) {
4828       const PetscInt idx     = c - cStart;
4829       PetscInt      *closure = PETSC_NULL;
4830       PetscInt       closureSize;
4831 
4832       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4833       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4834       for (v = 0; v < 4; ++v) {
4835         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4836       }
4837       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4838     }
4839   }
4840   /* TODO: Put in boundary faces with markers */
4841   if (!rank) {
4842     char args[32];
4843 
4844     /* Take away 'Q' for verbose output */
4845     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
4846     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
4847     ::tetrahedralize(args, &in, &out);
4848   }
4849   in.tetrahedronvolumelist = NULL;
4850 
4851   {
4852     const PetscInt numCorners  = 4;
4853     const PetscInt numCells    = out.numberoftetrahedra;
4854     const PetscInt numVertices = out.numberofpoints;
4855     const int     *cells       = out.tetrahedronlist;
4856     const double  *meshCoords  = out.pointlist;
4857     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4858 
4859     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4860     /* Set labels */
4861     for (v = 0; v < numVertices; ++v) {
4862       if (out.pointmarkerlist[v]) {
4863         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4864       }
4865     }
4866     if (interpolate) {
4867       PetscInt e, f;
4868 
4869       for (e = 0; e < out.numberofedges; e++) {
4870         if (out.edgemarkerlist[e]) {
4871           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4872           const PetscInt *edges;
4873           PetscInt        numEdges;
4874 
4875           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4876           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4877           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4878           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4879         }
4880       }
4881       for (f = 0; f < out.numberoftrifaces; f++) {
4882         if (out.trifacemarkerlist[f]) {
4883           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4884           const PetscInt *faces;
4885           PetscInt        numFaces;
4886 
4887           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4888           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4889           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4890           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4891         }
4892       }
4893     }
4894     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4895   }
4896   PetscFunctionReturn(0);
4897 }
4898 #endif
4899 
4900 #ifdef PETSC_HAVE_CTETGEN
4901 #include "ctetgen.h"
4902 
4903 #undef __FUNCT__
4904 #define __FUNCT__ "DMPlexGenerate_CTetgen"
4905 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4906 {
4907   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4908   const PetscInt dim  = 3;
4909   PLC           *in, *out;
4910   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4911   PetscMPIInt    rank;
4912   PetscErrorCode ierr;
4913 
4914   PetscFunctionBegin;
4915   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
4916   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4917   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4918   ierr = PLCCreate(&in);CHKERRQ(ierr);
4919   ierr = PLCCreate(&out);CHKERRQ(ierr);
4920   in->numberofpoints = vEnd - vStart;
4921   if (in->numberofpoints > 0) {
4922     PetscSection coordSection;
4923     Vec          coordinates;
4924     PetscScalar *array;
4925 
4926     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4927     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4928     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4929     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4930     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4931     for (v = vStart; v < vEnd; ++v) {
4932       const PetscInt idx = v - vStart;
4933       PetscInt       off, d, m;
4934 
4935       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4936       for (d = 0; d < dim; ++d) {
4937         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4938       }
4939       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
4940       in->pointmarkerlist[idx] = (int) m;
4941     }
4942     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4943   }
4944   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4945   in->numberoffacets = fEnd - fStart;
4946   if (in->numberoffacets > 0) {
4947     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
4948     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
4949     for (f = fStart; f < fEnd; ++f) {
4950       const PetscInt idx    = f - fStart;
4951       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
4952       polygon       *poly;
4953 
4954       in->facetlist[idx].numberofpolygons = 1;
4955       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
4956       in->facetlist[idx].numberofholes    = 0;
4957       in->facetlist[idx].holelist         = PETSC_NULL;
4958 
4959       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4960       for (p = 0; p < numPoints*2; p += 2) {
4961         const PetscInt point = points[p];
4962         if ((point >= vStart) && (point < vEnd)) {
4963           points[numVertices++] = point;
4964         }
4965       }
4966 
4967       poly = in->facetlist[idx].polygonlist;
4968       poly->numberofvertices = numVertices;
4969       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
4970       for (v = 0; v < numVertices; ++v) {
4971         const PetscInt vIdx = points[v] - vStart;
4972         poly->vertexlist[v] = vIdx;
4973       }
4974       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
4975       in->facetmarkerlist[idx] = (int) m;
4976       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4977     }
4978   }
4979   if (!rank) {
4980     TetGenOpts t;
4981 
4982     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4983     t.in        = boundary; /* Should go away */
4984     t.plc       = 1;
4985     t.quality   = 1;
4986     t.edgesout  = 1;
4987     t.zeroindex = 1;
4988     t.quiet     = 1;
4989     t.verbose   = verbose;
4990     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
4991     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4992   }
4993   {
4994     const PetscInt numCorners  = 4;
4995     const PetscInt numCells    = out->numberoftetrahedra;
4996     const PetscInt numVertices = out->numberofpoints;
4997     const int     *cells       = out->tetrahedronlist;
4998     const double  *meshCoords  = out->pointlist;
4999 
5000     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5001     /* Set labels */
5002     for (v = 0; v < numVertices; ++v) {
5003       if (out->pointmarkerlist[v]) {
5004         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5005       }
5006     }
5007     if (interpolate) {
5008       PetscInt e;
5009 
5010       for (e = 0; e < out->numberofedges; e++) {
5011         if (out->edgemarkerlist[e]) {
5012           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5013           const PetscInt *edges;
5014           PetscInt        numEdges;
5015 
5016           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5017           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5018           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5019           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5020         }
5021       }
5022       for (f = 0; f < out->numberoftrifaces; f++) {
5023         if (out->trifacemarkerlist[f]) {
5024           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5025           const PetscInt *faces;
5026           PetscInt        numFaces;
5027 
5028           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5029           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5030           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5031           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5032         }
5033       }
5034     }
5035     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5036   }
5037 
5038   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5039   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5040   PetscFunctionReturn(0);
5041 }
5042 
5043 #undef __FUNCT__
5044 #define __FUNCT__ "DMPlexRefine_CTetgen"
5045 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5046 {
5047   MPI_Comm       comm = ((PetscObject) dm)->comm;
5048   const PetscInt dim  = 3;
5049   PLC           *in, *out;
5050   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5051   PetscMPIInt    rank;
5052   PetscErrorCode ierr;
5053 
5054   PetscFunctionBegin;
5055   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5056   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5057   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5058   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5059   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5060   ierr = PLCCreate(&in);CHKERRQ(ierr);
5061   ierr = PLCCreate(&out);CHKERRQ(ierr);
5062   in->numberofpoints = vEnd - vStart;
5063   if (in->numberofpoints > 0) {
5064     PetscSection coordSection;
5065     Vec          coordinates;
5066     PetscScalar *array;
5067 
5068     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5069     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5070     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5071     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5072     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5073     for (v = vStart; v < vEnd; ++v) {
5074       const PetscInt idx = v - vStart;
5075       PetscInt       off, d, m;
5076 
5077       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5078       for (d = 0; d < dim; ++d) {
5079         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5080       }
5081       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5082       in->pointmarkerlist[idx] = (int) m;
5083     }
5084     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5085   }
5086   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5087   in->numberofcorners       = 4;
5088   in->numberoftetrahedra    = cEnd - cStart;
5089   in->tetrahedronvolumelist = maxVolumes;
5090   if (in->numberoftetrahedra > 0) {
5091     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5092     for (c = cStart; c < cEnd; ++c) {
5093       const PetscInt idx     = c - cStart;
5094       PetscInt      *closure = PETSC_NULL;
5095       PetscInt       closureSize;
5096 
5097       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5098       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5099       for (v = 0; v < 4; ++v) {
5100         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5101       }
5102       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5103     }
5104   }
5105   if (!rank) {
5106     TetGenOpts t;
5107 
5108     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5109     t.in        = dm; /* Should go away */
5110     t.refine    = 1;
5111     t.varvolume = 1;
5112     t.quality   = 1;
5113     t.edgesout  = 1;
5114     t.zeroindex = 1;
5115     t.quiet     = 1;
5116     t.verbose   = verbose; /* Change this */
5117     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5118     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5119   }
5120   {
5121     const PetscInt numCorners  = 4;
5122     const PetscInt numCells    = out->numberoftetrahedra;
5123     const PetscInt numVertices = out->numberofpoints;
5124     const int     *cells       = out->tetrahedronlist;
5125     const double  *meshCoords  = out->pointlist;
5126     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5127 
5128     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5129     /* Set labels */
5130     for (v = 0; v < numVertices; ++v) {
5131       if (out->pointmarkerlist[v]) {
5132         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5133       }
5134     }
5135     if (interpolate) {
5136       PetscInt e, f;
5137 
5138       for (e = 0; e < out->numberofedges; e++) {
5139         if (out->edgemarkerlist[e]) {
5140           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5141           const PetscInt *edges;
5142           PetscInt        numEdges;
5143 
5144           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5145           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5146           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5147           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5148         }
5149       }
5150       for (f = 0; f < out->numberoftrifaces; f++) {
5151         if (out->trifacemarkerlist[f]) {
5152           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5153           const PetscInt *faces;
5154           PetscInt        numFaces;
5155 
5156           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5157           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5158           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5159           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5160         }
5161       }
5162     }
5163     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5164   }
5165   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5166   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5167   PetscFunctionReturn(0);
5168 }
5169 #endif
5170 
5171 #undef __FUNCT__
5172 #define __FUNCT__ "DMPlexGenerate"
5173 /*@C
5174   DMPlexGenerate - Generates a mesh.
5175 
5176   Not Collective
5177 
5178   Input Parameters:
5179 + boundary - The DMPlex boundary object
5180 . name - The mesh generation package name
5181 - interpolate - Flag to create intermediate mesh elements
5182 
5183   Output Parameter:
5184 . mesh - The DMPlex object
5185 
5186   Level: intermediate
5187 
5188 .keywords: mesh, elements
5189 .seealso: DMPlexCreate(), DMRefine()
5190 @*/
5191 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5192 {
5193   PetscInt       dim;
5194   char           genname[1024];
5195   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5196   PetscErrorCode ierr;
5197 
5198   PetscFunctionBegin;
5199   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5200   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5201   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5202   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5203   if (flg) {name = genname;}
5204   if (name) {
5205     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5206     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5207     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5208   }
5209   switch(dim) {
5210   case 1:
5211     if (!name || isTriangle) {
5212 #ifdef PETSC_HAVE_TRIANGLE
5213       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5214 #else
5215       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5216 #endif
5217     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5218     break;
5219   case 2:
5220     if (!name || isCTetgen) {
5221 #ifdef PETSC_HAVE_CTETGEN
5222       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5223 #else
5224       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5225 #endif
5226     } else if (isTetgen) {
5227 #ifdef PETSC_HAVE_TETGEN
5228       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5229 #else
5230       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5231 #endif
5232     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5233     break;
5234   default:
5235     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5236   }
5237   PetscFunctionReturn(0);
5238 }
5239 
5240 typedef PetscInt CellRefiner;
5241 
5242 #undef __FUNCT__
5243 #define __FUNCT__ "GetDepthStart_Private"
5244 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5245 {
5246   PetscFunctionBegin;
5247   if (cStart) *cStart = 0;
5248   if (vStart) *vStart = depthSize[depth];
5249   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5250   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5251   PetscFunctionReturn(0);
5252 }
5253 
5254 #undef __FUNCT__
5255 #define __FUNCT__ "GetDepthEnd_Private"
5256 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5257 {
5258   PetscFunctionBegin;
5259   if (cEnd) *cEnd = depthSize[depth];
5260   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5261   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5262   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5263   PetscFunctionReturn(0);
5264 }
5265 
5266 #undef __FUNCT__
5267 #define __FUNCT__ "CellRefinerGetSizes"
5268 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5269 {
5270   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5271   PetscErrorCode ierr;
5272 
5273   PetscFunctionBegin;
5274   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5275   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5276   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5277   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5278   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);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 3:
5287     /* Hybrid 2D */
5288     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5289     cMax = PetscMin(cEnd, cMax);
5290     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5291     fMax = PetscMin(fEnd, fMax);
5292     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5293     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
5294     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5295     break;
5296   case 2:
5297     /* Hex 2D */
5298     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5299     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5300     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5301     break;
5302   default:
5303     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5304   }
5305   PetscFunctionReturn(0);
5306 }
5307 
5308 #undef __FUNCT__
5309 #define __FUNCT__ "CellRefinerSetConeSizes"
5310 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5311 {
5312   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5313   PetscErrorCode ierr;
5314 
5315   PetscFunctionBegin;
5316   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5317   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5318   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5319   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5320   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5321   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5322   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5323   switch(refiner) {
5324   case 1:
5325     /* Simplicial 2D */
5326     /* All cells have 3 faces */
5327     for(c = cStart; c < cEnd; ++c) {
5328       for(r = 0; r < 4; ++r) {
5329         const PetscInt newp = (c - cStart)*4 + r;
5330 
5331         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5332       }
5333     }
5334     /* Split faces have 2 vertices and the same cells as the parent */
5335     for(f = fStart; f < fEnd; ++f) {
5336       for(r = 0; r < 2; ++r) {
5337         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5338         PetscInt       size;
5339 
5340         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5341         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5342         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5343       }
5344     }
5345     /* Interior faces have 2 vertices and 2 cells */
5346     for(c = cStart; c < cEnd; ++c) {
5347       for(r = 0; r < 3; ++r) {
5348         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5349 
5350         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5351         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5352       }
5353     }
5354     /* Old vertices have identical supports */
5355     for(v = vStart; v < vEnd; ++v) {
5356       const PetscInt newp = vStartNew + (v - vStart);
5357       PetscInt       size;
5358 
5359       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5360       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5361     }
5362     /* Face vertices have 2 + cells*2 supports */
5363     for(f = fStart; f < fEnd; ++f) {
5364       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5365       PetscInt       size;
5366 
5367       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5368       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5369     }
5370     break;
5371   case 2:
5372     /* Hex 2D */
5373     /* All cells have 4 faces */
5374     for(c = cStart; c < cEnd; ++c) {
5375       for(r = 0; r < 4; ++r) {
5376         const PetscInt newp = (c - cStart)*4 + r;
5377 
5378         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5379       }
5380     }
5381     /* Split faces have 2 vertices and the same cells as the parent */
5382     for(f = fStart; f < fEnd; ++f) {
5383       for(r = 0; r < 2; ++r) {
5384         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5385         PetscInt       size;
5386 
5387         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5388         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5389         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5390       }
5391     }
5392     /* Interior faces have 2 vertices and 2 cells */
5393     for(c = cStart; c < cEnd; ++c) {
5394       for(r = 0; r < 4; ++r) {
5395         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5396 
5397         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5398         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5399       }
5400     }
5401     /* Old vertices have identical supports */
5402     for(v = vStart; v < vEnd; ++v) {
5403       const PetscInt newp = vStartNew + (v - vStart);
5404       PetscInt       size;
5405 
5406       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5407       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5408     }
5409     /* Face vertices have 2 + cells supports */
5410     for(f = fStart; f < fEnd; ++f) {
5411       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5412       PetscInt       size;
5413 
5414       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5415       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5416     }
5417     /* Cell vertices have 4 supports */
5418     for(c = cStart; c < cEnd; ++c) {
5419       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5420 
5421       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5422     }
5423     break;
5424   case 3:
5425     /* Hybrid 2D */
5426     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5427     cMax = PetscMin(cEnd, cMax);
5428     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5429     fMax = PetscMin(fEnd, fMax);
5430     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5431     /* Interior cells have 3 faces */
5432     for(c = cStart; c < cMax; ++c) {
5433       for(r = 0; r < 4; ++r) {
5434         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5435 
5436         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5437       }
5438     }
5439     /* Hybrid cells have 4 faces */
5440     for(c = cMax; c < cEnd; ++c) {
5441       for(r = 0; r < 2; ++r) {
5442         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5443 
5444         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5445       }
5446     }
5447     /* Interior split faces have 2 vertices and the same cells as the parent */
5448     for(f = fStart; f < fMax; ++f) {
5449       for(r = 0; r < 2; ++r) {
5450         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5451         PetscInt       size;
5452 
5453         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5454         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5455         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5456       }
5457     }
5458     /* Interior cell faces have 2 vertices and 2 cells */
5459     for(c = cStart; c < cMax; ++c) {
5460       for(r = 0; r < 3; ++r) {
5461         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5462 
5463         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5464         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5465       }
5466     }
5467     /* Hybrid faces have 2 vertices and the same cells */
5468     for(f = fMax; f < fEnd; ++f) {
5469       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5470       PetscInt       size;
5471 
5472       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5473       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5474       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5475     }
5476     /* Hybrid cell faces have 2 vertices and 2 cells */
5477     for(c = cMax; c < cEnd; ++c) {
5478       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5479 
5480       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5481       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5482     }
5483     /* Old vertices have identical supports */
5484     for(v = vStart; v < vEnd; ++v) {
5485       const PetscInt newp = vStartNew + (v - vStart);
5486       PetscInt       size;
5487 
5488       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5489       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5490     }
5491     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5492     for(f = fStart; f < fMax; ++f) {
5493       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5494       const PetscInt *support;
5495       PetscInt        size, newSize = 2, s;
5496 
5497       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5498       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5499       for(s = 0; s < size; ++s) {
5500         if (support[s] >= cMax) {
5501           newSize += 1;
5502         } else {
5503           newSize += 2;
5504         }
5505       }
5506       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5507     }
5508     break;
5509   default:
5510     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5511   }
5512   PetscFunctionReturn(0);
5513 }
5514 
5515 #undef __FUNCT__
5516 #define __FUNCT__ "CellRefinerSetCones"
5517 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5518 {
5519   PetscInt       depth, cStart, cEnd, cMax, cStartNew, cEndNew, c, vStart, vEnd, vMax, vStartNew, vEndNew, v, fStart, fEnd, fMax, fStartNew, fEndNew, f, eStart, eEnd, eMax, eStartNew, eEndNew, r, p;
5520   PetscInt       maxSupportSize, *supportRef;
5521   PetscErrorCode ierr;
5522 
5523   PetscFunctionBegin;
5524   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5525   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5526   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5527   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5528   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5529   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5530   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5531   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5532   switch(refiner) {
5533   case 1:
5534     /* Simplicial 2D */
5535     /*
5536      2
5537      |\
5538      | \
5539      |  \
5540      |   \
5541      | C  \
5542      |     \
5543      |      \
5544      2---1---1
5545      |\  D  / \
5546      | 2   0   \
5547      |A \ /  B  \
5548      0---0-------1
5549      */
5550     /* All cells have 3 faces */
5551     for(c = cStart; c < cEnd; ++c) {
5552       const PetscInt  newp = cStartNew + (c - cStart)*4;
5553       const PetscInt *cone, *ornt;
5554       PetscInt        coneNew[3], orntNew[3];
5555 
5556       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5557       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5558       /* A triangle */
5559       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5560       orntNew[0] = ornt[0];
5561       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5562       orntNew[1] = -2;
5563       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5564       orntNew[2] = ornt[2];
5565       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5566       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5567 #if 1
5568       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);
5569       for(p = 0; p < 3; ++p) {
5570         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);
5571       }
5572 #endif
5573       /* B triangle */
5574       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5575       orntNew[0] = ornt[0];
5576       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5577       orntNew[1] = ornt[1];
5578       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5579       orntNew[2] = -2;
5580       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5581       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5582 #if 1
5583       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);
5584       for(p = 0; p < 3; ++p) {
5585         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);
5586       }
5587 #endif
5588       /* C triangle */
5589       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5590       orntNew[0] = -2;
5591       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5592       orntNew[1] = ornt[1];
5593       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5594       orntNew[2] = ornt[2];
5595       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5596       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5597 #if 1
5598       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);
5599       for(p = 0; p < 3; ++p) {
5600         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);
5601       }
5602 #endif
5603       /* D triangle */
5604       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5605       orntNew[0] = 0;
5606       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5607       orntNew[1] = 0;
5608       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5609       orntNew[2] = 0;
5610       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5611       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5612 #if 1
5613       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);
5614       for(p = 0; p < 3; ++p) {
5615         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);
5616       }
5617 #endif
5618     }
5619     /* Split faces have 2 vertices and the same cells as the parent */
5620     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5621     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5622     for(f = fStart; f < fEnd; ++f) {
5623       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5624 
5625       for(r = 0; r < 2; ++r) {
5626         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5627         const PetscInt *cone, *support;
5628         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5629 
5630         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5631         coneNew[0] = vStartNew + (cone[0] - vStart);
5632         coneNew[1] = vStartNew + (cone[1] - vStart);
5633         coneNew[(r+1)%2] = newv;
5634         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5635 #if 1
5636         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5637         for(p = 0; p < 2; ++p) {
5638           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);
5639         }
5640 #endif
5641         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5642         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5643         for(s = 0; s < supportSize; ++s) {
5644           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5645           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5646           for(c = 0; c < coneSize; ++c) {
5647             if (cone[c] == f) {
5648               break;
5649             }
5650           }
5651           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5652         }
5653         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5654 #if 1
5655         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5656         for(p = 0; p < supportSize; ++p) {
5657           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);
5658         }
5659 #endif
5660       }
5661     }
5662     /* Interior faces have 2 vertices and 2 cells */
5663     for(c = cStart; c < cEnd; ++c) {
5664       const PetscInt *cone;
5665 
5666       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5667       for(r = 0; r < 3; ++r) {
5668         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5669         PetscInt       coneNew[2];
5670         PetscInt       supportNew[2];
5671 
5672         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5673         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5674         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5675 #if 1
5676         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5677         for(p = 0; p < 2; ++p) {
5678           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);
5679         }
5680 #endif
5681         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5682         supportNew[1] = (c - cStart)*4 + 3;
5683         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5684 #if 1
5685         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5686         for(p = 0; p < 2; ++p) {
5687           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);
5688         }
5689 #endif
5690       }
5691     }
5692     /* Old vertices have identical supports */
5693     for(v = vStart; v < vEnd; ++v) {
5694       const PetscInt  newp = vStartNew + (v - vStart);
5695       const PetscInt *support, *cone;
5696       PetscInt        size, s;
5697 
5698       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5699       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5700       for(s = 0; s < size; ++s) {
5701         PetscInt r = 0;
5702 
5703         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5704         if (cone[1] == v) r = 1;
5705         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5706       }
5707       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5708 #if 1
5709       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5710       for(p = 0; p < size; ++p) {
5711         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);
5712       }
5713 #endif
5714     }
5715     /* Face vertices have 2 + cells*2 supports */
5716     for(f = fStart; f < fEnd; ++f) {
5717       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5718       const PetscInt *cone, *support;
5719       PetscInt        size, s;
5720 
5721       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5722       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5723       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5724       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5725       for(s = 0; s < size; ++s) {
5726         PetscInt r = 0;
5727 
5728         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5729         if      (cone[1] == f) r = 1;
5730         else if (cone[2] == f) r = 2;
5731         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5732         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5733       }
5734       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5735 #if 1
5736       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5737       for(p = 0; p < 2+size*2; ++p) {
5738         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);
5739       }
5740 #endif
5741     }
5742     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5743     break;
5744   case 2:
5745     /* Hex 2D */
5746     /*
5747      3---------2---------2
5748      |         |         |
5749      |    D    2    C    |
5750      |         |         |
5751      3----3----0----1----1
5752      |         |         |
5753      |    A    0    B    |
5754      |         |         |
5755      0---------0---------1
5756      */
5757     /* All cells have 4 faces */
5758     for(c = cStart; c < cEnd; ++c) {
5759       const PetscInt  newp = (c - cStart)*4;
5760       const PetscInt *cone, *ornt;
5761       PetscInt        coneNew[4], orntNew[4];
5762 
5763       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5764       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5765       /* A quad */
5766       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5767       orntNew[0] = ornt[0];
5768       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5769       orntNew[1] = 0;
5770       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5771       orntNew[2] = -2;
5772       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5773       orntNew[3] = ornt[3];
5774       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5775       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5776 #if 1
5777       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);
5778       for(p = 0; p < 4; ++p) {
5779         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);
5780       }
5781 #endif
5782       /* B quad */
5783       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5784       orntNew[0] = ornt[0];
5785       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5786       orntNew[1] = ornt[1];
5787       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5788       orntNew[2] = 0;
5789       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5790       orntNew[3] = -2;
5791       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5792       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5793 #if 1
5794       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);
5795       for(p = 0; p < 4; ++p) {
5796         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);
5797       }
5798 #endif
5799       /* C quad */
5800       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5801       orntNew[0] = -2;
5802       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5803       orntNew[1] = ornt[1];
5804       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5805       orntNew[2] = ornt[2];
5806       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5807       orntNew[3] = 0;
5808       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5809       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5810 #if 1
5811       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);
5812       for(p = 0; p < 4; ++p) {
5813         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);
5814       }
5815 #endif
5816       /* D quad */
5817       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5818       orntNew[0] = 0;
5819       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5820       orntNew[1] = -2;
5821       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5822       orntNew[2] = ornt[2];
5823       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
5824       orntNew[3] = ornt[3];
5825       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5826       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5827 #if 1
5828       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);
5829       for(p = 0; p < 4; ++p) {
5830         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);
5831       }
5832 #endif
5833     }
5834     /* Split faces have 2 vertices and the same cells as the parent */
5835     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5836     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5837     for(f = fStart; f < fEnd; ++f) {
5838       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5839 
5840       for(r = 0; r < 2; ++r) {
5841         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5842         const PetscInt *cone, *support;
5843         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5844 
5845         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5846         coneNew[0] = vStartNew + (cone[0] - vStart);
5847         coneNew[1] = vStartNew + (cone[1] - vStart);
5848         coneNew[(r+1)%2] = newv;
5849         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5850 #if 1
5851         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5852         for(p = 0; p < 2; ++p) {
5853           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);
5854         }
5855 #endif
5856         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5857         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5858         for(s = 0; s < supportSize; ++s) {
5859           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5860           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5861           for(c = 0; c < coneSize; ++c) {
5862             if (cone[c] == f) {
5863               break;
5864             }
5865           }
5866           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
5867         }
5868         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5869 #if 1
5870         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5871         for(p = 0; p < supportSize; ++p) {
5872           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);
5873         }
5874 #endif
5875       }
5876     }
5877     /* Interior faces have 2 vertices and 2 cells */
5878     for(c = cStart; c < cEnd; ++c) {
5879       const PetscInt *cone;
5880       PetscInt        coneNew[2], supportNew[2];
5881 
5882       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5883       for(r = 0; r < 4; ++r) {
5884         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5885 
5886         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
5887         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
5888         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5889 #if 1
5890         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5891         for(p = 0; p < 2; ++p) {
5892           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);
5893         }
5894 #endif
5895         supportNew[0] = (c - cStart)*4 + r;
5896         supportNew[1] = (c - cStart)*4 + (r+1)%4;
5897         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5898 #if 1
5899         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5900         for(p = 0; p < 2; ++p) {
5901           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);
5902         }
5903 #endif
5904       }
5905     }
5906     /* Old vertices have identical supports */
5907     for(v = vStart; v < vEnd; ++v) {
5908       const PetscInt  newp = vStartNew + (v - vStart);
5909       const PetscInt *support, *cone;
5910       PetscInt        size, s;
5911 
5912       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5913       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5914       for(s = 0; s < size; ++s) {
5915         PetscInt r = 0;
5916 
5917         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5918         if (cone[1] == v) r = 1;
5919         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5920       }
5921       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5922 #if 1
5923       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5924       for(p = 0; p < size; ++p) {
5925         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);
5926       }
5927 #endif
5928     }
5929     /* Face vertices have 2 + cells supports */
5930     for(f = fStart; f < fEnd; ++f) {
5931       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5932       const PetscInt *cone, *support;
5933       PetscInt        size, s;
5934 
5935       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5936       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5937       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5938       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5939       for(s = 0; s < size; ++s) {
5940         PetscInt r = 0;
5941 
5942         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5943         if      (cone[1] == f) r = 1;
5944         else if (cone[2] == f) r = 2;
5945         else if (cone[3] == f) r = 3;
5946         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
5947       }
5948       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5949 #if 1
5950       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5951       for(p = 0; p < 2+size; ++p) {
5952         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);
5953       }
5954 #endif
5955     }
5956     /* Cell vertices have 4 supports */
5957     for(c = cStart; c < cEnd; ++c) {
5958       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5959       PetscInt       supportNew[4];
5960 
5961       for(r = 0; r < 4; ++r) {
5962         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5963       }
5964       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5965     }
5966     break;
5967   case 3:
5968     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5969     cMax = PetscMin(cEnd, cMax);
5970     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5971     fMax = PetscMin(fEnd, fMax);
5972     /* Interior cells have 3 faces */
5973     for(c = cStart; c < cMax; ++c) {
5974       const PetscInt  newp = cStartNew + (c - cStart)*4;
5975       const PetscInt *cone, *ornt;
5976       PetscInt        coneNew[3], orntNew[3];
5977 
5978       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5979       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5980       /* A triangle */
5981       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5982       orntNew[0] = ornt[0];
5983       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
5984       orntNew[1] = -2;
5985       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5986       orntNew[2] = ornt[2];
5987       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5988       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5989 #if 1
5990       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);
5991       for(p = 0; p < 3; ++p) {
5992         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);
5993       }
5994 #endif
5995       /* B triangle */
5996       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5997       orntNew[0] = ornt[0];
5998       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5999       orntNew[1] = ornt[1];
6000       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6001       orntNew[2] = -2;
6002       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6003       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6004 #if 1
6005       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);
6006       for(p = 0; p < 3; ++p) {
6007         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);
6008       }
6009 #endif
6010       /* C triangle */
6011       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6012       orntNew[0] = -2;
6013       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6014       orntNew[1] = ornt[1];
6015       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6016       orntNew[2] = ornt[2];
6017       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6018       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6019 #if 1
6020       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);
6021       for(p = 0; p < 3; ++p) {
6022         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);
6023       }
6024 #endif
6025       /* D triangle */
6026       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6027       orntNew[0] = 0;
6028       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6029       orntNew[1] = 0;
6030       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6031       orntNew[2] = 0;
6032       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6033       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6034 #if 1
6035       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);
6036       for(p = 0; p < 3; ++p) {
6037         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);
6038       }
6039 #endif
6040     }
6041     /*
6042      2----3----3
6043      |         |
6044      |    B    |
6045      |         |
6046      0----4--- 1
6047      |         |
6048      |    A    |
6049      |         |
6050      0----2----1
6051      */
6052     /* Hybrid cells have 4 faces */
6053     for(c = cMax; c < cEnd; ++c) {
6054       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6055       const PetscInt *cone, *ornt;
6056       PetscInt        coneNew[4], orntNew[4];
6057 
6058       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6059       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6060       /* A quad */
6061       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6062       orntNew[0] = ornt[0];
6063       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6064       orntNew[1] = ornt[1];
6065       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6066       orntNew[2] = 0;
6067       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6068       orntNew[3] = 0;
6069       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6070       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6071 #if 1
6072       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);
6073       for(p = 0; p < 4; ++p) {
6074         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);
6075       }
6076 #endif
6077       /* B quad */
6078       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6079       orntNew[0] = ornt[0];
6080       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6081       orntNew[1] = ornt[1];
6082       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6083       orntNew[2] = 0;
6084       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6085       orntNew[3] = 0;
6086       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6087       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6088 #if 1
6089       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);
6090       for(p = 0; p < 4; ++p) {
6091         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);
6092       }
6093 #endif
6094     }
6095     /* Interior split faces have 2 vertices and the same cells as the parent */
6096     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6097     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6098     for(f = fStart; f < fMax; ++f) {
6099       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6100 
6101       for(r = 0; r < 2; ++r) {
6102         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6103         const PetscInt *cone, *support;
6104         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6105 
6106         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6107         coneNew[0] = vStartNew + (cone[0] - vStart);
6108         coneNew[1] = vStartNew + (cone[1] - vStart);
6109         coneNew[(r+1)%2] = newv;
6110         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6111 #if 1
6112         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6113         for(p = 0; p < 2; ++p) {
6114           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);
6115         }
6116 #endif
6117         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6118         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6119         for(s = 0; s < supportSize; ++s) {
6120           if (support[s] >= cMax) {
6121             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6122           } else {
6123             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6124             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6125             for(c = 0; c < coneSize; ++c) {
6126               if (cone[c] == f) {
6127                 break;
6128               }
6129             }
6130             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6131           }
6132         }
6133         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6134 #if 1
6135         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6136         for(p = 0; p < supportSize; ++p) {
6137           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);
6138         }
6139 #endif
6140       }
6141     }
6142     /* Interior cell faces have 2 vertices and 2 cells */
6143     for(c = cStart; c < cMax; ++c) {
6144       const PetscInt *cone;
6145 
6146       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6147       for(r = 0; r < 3; ++r) {
6148         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6149         PetscInt       coneNew[2];
6150         PetscInt       supportNew[2];
6151 
6152         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6153         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6154         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6155 #if 1
6156         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6157         for(p = 0; p < 2; ++p) {
6158           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);
6159         }
6160 #endif
6161         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6162         supportNew[1] = (c - cStart)*4 + 3;
6163         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6164 #if 1
6165         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6166         for(p = 0; p < 2; ++p) {
6167           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);
6168         }
6169 #endif
6170       }
6171     }
6172     /* Interior hybrid faces have 2 vertices and the same cells */
6173     for(f = fMax; f < fEnd; ++f) {
6174       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6175       const PetscInt *cone;
6176       const PetscInt *support;
6177       PetscInt        coneNew[2];
6178       PetscInt        supportNew[2];
6179       PetscInt        size, s, r;
6180 
6181       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6182       coneNew[0] = vStartNew + (cone[0] - vStart);
6183       coneNew[1] = vStartNew + (cone[1] - vStart);
6184       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6185 #if 1
6186       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6187       for(p = 0; p < 2; ++p) {
6188         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);
6189       }
6190 #endif
6191       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6192       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6193       for(s = 0; s < size; ++s) {
6194         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6195         for(r = 0; r < 2; ++r) {
6196           if (cone[r+2] == f) break;
6197         }
6198         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6199       }
6200       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6201 #if 1
6202       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6203       for(p = 0; p < size; ++p) {
6204         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);
6205       }
6206 #endif
6207     }
6208     /* Cell hybrid faces have 2 vertices and 2 cells */
6209     for(c = cMax; c < cEnd; ++c) {
6210       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6211       const PetscInt *cone;
6212       PetscInt        coneNew[2];
6213       PetscInt        supportNew[2];
6214 
6215       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6216       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6217       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6218       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6219 #if 1
6220       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6221       for(p = 0; p < 2; ++p) {
6222         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);
6223       }
6224 #endif
6225       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6226       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6227       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6228 #if 1
6229       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6230       for(p = 0; p < 2; ++p) {
6231         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);
6232       }
6233 #endif
6234     }
6235     /* Old vertices have identical supports */
6236     for(v = vStart; v < vEnd; ++v) {
6237       const PetscInt  newp = vStartNew + (v - vStart);
6238       const PetscInt *support, *cone;
6239       PetscInt        size, s;
6240 
6241       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6242       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6243       for(s = 0; s < size; ++s) {
6244         if (support[s] >= fMax) {
6245           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6246         } else {
6247           PetscInt r = 0;
6248 
6249           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6250           if (cone[1] == v) r = 1;
6251           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6252         }
6253       }
6254       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6255 #if 1
6256       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6257       for(p = 0; p < size; ++p) {
6258         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);
6259       }
6260 #endif
6261     }
6262     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6263     for(f = fStart; f < fMax; ++f) {
6264       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6265       const PetscInt *cone, *support;
6266       PetscInt        size, newSize = 2, s;
6267 
6268       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6269       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6270       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6271       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6272       for(s = 0; s < size; ++s) {
6273         PetscInt r = 0;
6274 
6275         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6276         if (support[s] >= cMax) {
6277           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6278           newSize += 1;
6279         } else {
6280           if      (cone[1] == f) r = 1;
6281           else if (cone[2] == f) r = 2;
6282           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6283           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6284           newSize += 2;
6285         }
6286       }
6287       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6288 #if 1
6289       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6290       for(p = 0; p < newSize; ++p) {
6291         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);
6292       }
6293 #endif
6294     }
6295     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6296     break;
6297   default:
6298     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6299   }
6300   PetscFunctionReturn(0);
6301 }
6302 
6303 #undef __FUNCT__
6304 #define __FUNCT__ "CellRefinerSetCoordinates"
6305 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6306 {
6307   PetscSection   coordSection, coordSectionNew;
6308   Vec            coordinates, coordinatesNew;
6309   PetscScalar   *coords, *coordsNew;
6310   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6311   PetscErrorCode ierr;
6312 
6313   PetscFunctionBegin;
6314   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6315   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6316   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6317   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6318   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6319   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6320   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6321   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6322   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6323   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6324   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6325   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6326   if (fMax < 0) fMax = fEnd;
6327   switch(refiner) {
6328   case 1:
6329   case 2:
6330   case 3:
6331     /* Simplicial and Hex 2D */
6332     /* All vertices have the dim coordinates */
6333     for(v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6334       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6335       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6336     }
6337     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6338     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6339     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6340     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6341     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6342     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6343     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6344     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6345     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6346     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6347     /* Old vertices have the same coordinates */
6348     for(v = vStart; v < vEnd; ++v) {
6349       const PetscInt newv = vStartNew + (v - vStart);
6350       PetscInt       off, offnew, d;
6351 
6352       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6353       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6354       for(d = 0; d < dim; ++d) {
6355         coordsNew[offnew+d] = coords[off+d];
6356       }
6357     }
6358     /* Face vertices have the average of endpoint coordinates */
6359     for(f = fStart; f < fMax; ++f) {
6360       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6361       const PetscInt *cone;
6362       PetscInt        coneSize, offA, offB, offnew, d;
6363 
6364       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6365       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6366       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6367       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6368       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6369       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6370       for(d = 0; d < dim; ++d) {
6371         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6372       }
6373     }
6374     /* Just Hex 2D */
6375     if (refiner == 2) {
6376       /* Cell vertices have the average of corner coordinates */
6377       for(c = cStart; c < cEnd; ++c) {
6378         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6379         PetscInt      *cone = PETSC_NULL;
6380         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6381 
6382         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6383         for(p = 0; p < closureSize*2; p += 2) {
6384           const PetscInt point = cone[p];
6385           if ((point >= vStart) && (point < vEnd)) {
6386             cone[coneSize++] = point;
6387           }
6388         }
6389         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6390         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6391         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6392         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6393         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6394         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6395         for(d = 0; d < dim; ++d) {
6396           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6397         }
6398         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6399       }
6400     }
6401     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6402     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6403     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6404     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6405     break;
6406   default:
6407     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6408   }
6409   PetscFunctionReturn(0);
6410 }
6411 
6412 #undef __FUNCT__
6413 #define __FUNCT__ "DMPlexCreateProcessSF"
6414 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6415 {
6416   PetscInt           numRoots, numLeaves, l;
6417   const PetscInt    *localPoints;
6418   const PetscSFNode *remotePoints;
6419   PetscInt          *localPointsNew;
6420   PetscSFNode       *remotePointsNew;
6421   PetscInt          *ranks, *ranksNew;
6422   PetscErrorCode     ierr;
6423 
6424   PetscFunctionBegin;
6425   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6426   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6427   for(l = 0; l < numLeaves; ++l) {
6428     ranks[l] = remotePoints[l].rank;
6429   }
6430   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6431   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6432   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6433   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6434   for(l = 0; l < numLeaves; ++l) {
6435     ranksNew[l]              = ranks[l];
6436     localPointsNew[l]        = l;
6437     remotePointsNew[l].index = 0;
6438     remotePointsNew[l].rank  = ranksNew[l];
6439   }
6440   ierr = PetscFree(ranks);CHKERRQ(ierr);
6441   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6442   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6443   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6444   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6445   PetscFunctionReturn(0);
6446 }
6447 
6448 #undef __FUNCT__
6449 #define __FUNCT__ "CellRefinerCreateSF"
6450 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6451 {
6452   PetscSF            sf, sfNew, sfProcess;
6453   IS                 processRanks;
6454   MPI_Datatype       depthType;
6455   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6456   const PetscInt    *localPoints, *neighbors;
6457   const PetscSFNode *remotePoints;
6458   PetscInt          *localPointsNew;
6459   PetscSFNode       *remotePointsNew;
6460   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6461   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6462   PetscErrorCode     ierr;
6463 
6464   PetscFunctionBegin;
6465   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6466   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6467   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6468   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6469   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6470   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6471   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6472   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6473   switch(refiner) {
6474   case 3:
6475     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6476     cMax = PetscMin(cEnd, cMax);
6477     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6478     fMax = PetscMin(fEnd, fMax);
6479   }
6480   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6481   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6482   /* Caculate size of new SF */
6483   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6484   if (numRoots < 0) PetscFunctionReturn(0);
6485   for(l = 0; l < numLeaves; ++l) {
6486     const PetscInt p = localPoints[l];
6487 
6488     switch(refiner) {
6489     case 1:
6490       /* Simplicial 2D */
6491       if ((p >= vStart) && (p < vEnd)) {
6492         /* Old vertices stay the same */
6493         ++numLeavesNew;
6494       } else if ((p >= fStart) && (p < fEnd)) {
6495         /* Old faces add new faces and vertex */
6496         numLeavesNew += 1 + 2;
6497       } else if ((p >= cStart) && (p < cEnd)) {
6498         /* Old cells add new cells and interior faces */
6499         numLeavesNew += 4 + 3;
6500       }
6501       break;
6502     case 2:
6503       /* Hex 2D */
6504       if ((p >= vStart) && (p < vEnd)) {
6505         /* Old vertices stay the same */
6506         ++numLeavesNew;
6507       } else if ((p >= fStart) && (p < fEnd)) {
6508         /* Old faces add new faces and vertex */
6509         numLeavesNew += 1 + 2;
6510       } else if ((p >= cStart) && (p < cEnd)) {
6511         /* Old cells add new cells and interior faces */
6512         numLeavesNew += 4 + 4;
6513       }
6514       break;
6515     default:
6516       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6517     }
6518   }
6519   /* Communicate depthSizes for each remote rank */
6520   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6521   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6522   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6523   ierr = PetscMalloc7(depth+1,PetscInt,&depthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthMaxOld,numNeighbors,PetscInt,&rvStart,numNeighbors,PetscInt,&reStart,numNeighbors,PetscInt,&rfStart,numNeighbors,PetscInt,&rcStart);CHKERRQ(ierr);
6524   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6525   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6526   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6527   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6528   for(n = 0; n < numNeighbors; ++n) {
6529     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6530   }
6531   depthSizeOld[depth]   = cMax;
6532   depthSizeOld[0]       = vMax;
6533   depthSizeOld[depth-1] = fMax;
6534   depthSizeOld[1]       = eMax;
6535   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6536   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6537   depthSizeOld[depth]   = cEnd - cStart;
6538   depthSizeOld[0]       = vEnd - vStart;
6539   depthSizeOld[depth-1] = fEnd - fStart;
6540   depthSizeOld[1]       = eEnd - eStart;
6541   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6542   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6543   for(n = 0; n < numNeighbors; ++n) {
6544     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6545   }
6546   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6547   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6548   /* Calculate new point SF */
6549   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6550   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6551   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6552   for(l = 0, m = 0; l < numLeaves; ++l) {
6553     PetscInt    p     = localPoints[l];
6554     PetscInt    rp    = remotePoints[l].index, n;
6555     PetscMPIInt rrank = remotePoints[l].rank;
6556 
6557     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6558     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6559     switch(refiner) {
6560     case 1:
6561       /* Simplicial 2D */
6562       if ((p >= vStart) && (p < vEnd)) {
6563         /* Old vertices stay the same */
6564         localPointsNew[m]        = vStartNew     + (p  - vStart);
6565         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6566         remotePointsNew[m].rank  = rrank;
6567         ++m;
6568       } else if ((p >= fStart) && (p < fEnd)) {
6569         /* Old faces add new faces and vertex */
6570         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6571         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6572         remotePointsNew[m].rank  = rrank;
6573         ++m;
6574         for(r = 0; r < 2; ++r, ++m) {
6575           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6576           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6577           remotePointsNew[m].rank  = rrank;
6578         }
6579       } else if ((p >= cStart) && (p < cEnd)) {
6580         /* Old cells add new cells and interior faces */
6581         for(r = 0; r < 4; ++r, ++m) {
6582           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6583           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6584           remotePointsNew[m].rank  = rrank;
6585         }
6586         for(r = 0; r < 3; ++r, ++m) {
6587           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6588           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6589           remotePointsNew[m].rank  = rrank;
6590         }
6591       }
6592       break;
6593     case 2:
6594       /* Hex 2D */
6595       if ((p >= vStart) && (p < vEnd)) {
6596         /* Old vertices stay the same */
6597         localPointsNew[m]        = vStartNew     + (p  - vStart);
6598         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6599         remotePointsNew[m].rank  = rrank;
6600         ++m;
6601       } else if ((p >= fStart) && (p < fEnd)) {
6602         /* Old faces add new faces and vertex */
6603         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6604         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6605         remotePointsNew[m].rank  = rrank;
6606         ++m;
6607         for(r = 0; r < 2; ++r, ++m) {
6608           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6609           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6610           remotePointsNew[m].rank  = rrank;
6611         }
6612       } else if ((p >= cStart) && (p < cEnd)) {
6613         /* Old cells add new cells and interior faces */
6614         for(r = 0; r < 4; ++r, ++m) {
6615           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6616           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6617           remotePointsNew[m].rank  = rrank;
6618         }
6619         for(r = 0; r < 4; ++r, ++m) {
6620           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6621           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6622           remotePointsNew[m].rank  = rrank;
6623         }
6624       }
6625       break;
6626     case 3:
6627       /* Hybrid simplicial 2D */
6628       if ((p >= vStart) && (p < vEnd)) {
6629         /* Old vertices stay the same */
6630         localPointsNew[m]        = vStartNew     + (p  - vStart);
6631         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6632         remotePointsNew[m].rank  = rrank;
6633         ++m;
6634       } else if ((p >= fStart) && (p < fMax)) {
6635         /* Old interior faces add new faces and vertex */
6636         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6637         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6638         remotePointsNew[m].rank  = rrank;
6639         ++m;
6640         for(r = 0; r < 2; ++r, ++m) {
6641           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6642           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6643           remotePointsNew[m].rank  = rrank;
6644         }
6645       } else if ((p >= fMax) && (p < fEnd)) {
6646         /* Old hybrid faces stay the same */
6647         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6648         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6649         remotePointsNew[m].rank  = rrank;
6650         ++m;
6651       } else if ((p >= cStart) && (p < cMax)) {
6652         /* Old interior cells add new cells and interior faces */
6653         for(r = 0; r < 4; ++r, ++m) {
6654           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6655           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6656           remotePointsNew[m].rank  = rrank;
6657         }
6658         for(r = 0; r < 3; ++r, ++m) {
6659           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6660           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6661           remotePointsNew[m].rank  = rrank;
6662         }
6663       } else if ((p >= cStart) && (p < cMax)) {
6664         /* Old hybrid cells add new cells and hybrid face */
6665         for(r = 0; r < 2; ++r, ++m) {
6666           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6667           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6668           remotePointsNew[m].rank  = rrank;
6669         }
6670         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6671         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
6672         remotePointsNew[m].rank  = rrank;
6673         ++m;
6674       }
6675       break;
6676     default:
6677       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6678     }
6679   }
6680   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6681   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6682   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6683   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6684   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6685   PetscFunctionReturn(0);
6686 }
6687 
6688 #undef __FUNCT__
6689 #define __FUNCT__ "CellRefinerCreateLabels"
6690 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6691 {
6692   PetscInt       numLabels, l;
6693   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
6694   PetscErrorCode ierr;
6695 
6696   PetscFunctionBegin;
6697   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6698   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6699   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6700   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6701   cStartNew = 0;
6702   vStartNew = depthSize[2];
6703   fStartNew = depthSize[2] + depthSize[0];
6704   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6705   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6706   switch(refiner) {
6707   case 3:
6708     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6709     cMax = PetscMin(cEnd, cMax);
6710     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6711     fMax = PetscMin(fEnd, fMax);
6712   }
6713   for(l = 0; l < numLabels; ++l) {
6714     DMLabel         label, labelNew;
6715     const char     *lname;
6716     PetscBool       isDepth;
6717     IS              valueIS;
6718     const PetscInt *values;
6719     PetscInt        numValues, val;
6720 
6721     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6722     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6723     if (isDepth) continue;
6724     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6725     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6726     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6727     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6728     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6729     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6730     for(val = 0; val < numValues; ++val) {
6731       IS              pointIS;
6732       const PetscInt *points;
6733       PetscInt        numPoints, n;
6734 
6735       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6736       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6737       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6738       for(n = 0; n < numPoints; ++n) {
6739         const PetscInt p = points[n];
6740         switch(refiner) {
6741         case 1:
6742           /* Simplicial 2D */
6743           if ((p >= vStart) && (p < vEnd)) {
6744             /* Old vertices stay the same */
6745             newp = vStartNew + (p - vStart);
6746             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6747           } else if ((p >= fStart) && (p < fEnd)) {
6748             /* Old faces add new faces and vertex */
6749             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6750             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6751             for(r = 0; r < 2; ++r) {
6752               newp = fStartNew + (p - fStart)*2 + r;
6753               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6754             }
6755           } else if ((p >= cStart) && (p < cEnd)) {
6756             /* Old cells add new cells and interior faces */
6757             for(r = 0; r < 4; ++r) {
6758               newp = cStartNew + (p - cStart)*4 + r;
6759               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6760             }
6761             for(r = 0; r < 3; ++r) {
6762               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6763               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6764             }
6765           }
6766           break;
6767         case 2:
6768           /* Hex 2D */
6769           if ((p >= vStart) && (p < vEnd)) {
6770             /* Old vertices stay the same */
6771             newp = vStartNew + (p - vStart);
6772             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6773           } else if ((p >= fStart) && (p < fEnd)) {
6774             /* Old faces add new faces and vertex */
6775             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6776             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6777             for(r = 0; r < 2; ++r) {
6778               newp = fStartNew + (p - fStart)*2 + r;
6779               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6780             }
6781           } else if ((p >= cStart) && (p < cEnd)) {
6782             /* Old cells add new cells and interior faces and vertex */
6783             for(r = 0; r < 4; ++r) {
6784               newp = cStartNew + (p - cStart)*4 + r;
6785               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6786             }
6787             for(r = 0; r < 4; ++r) {
6788               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6789               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6790             }
6791             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6792             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6793           }
6794           break;
6795         case 3:
6796           /* Hybrid simplicial 2D */
6797           if ((p >= vStart) && (p < vEnd)) {
6798             /* Old vertices stay the same */
6799             newp = vStartNew + (p - vStart);
6800             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6801           } else if ((p >= fStart) && (p < fMax)) {
6802             /* Old interior faces add new faces and vertex */
6803             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6804             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6805             for(r = 0; r < 2; ++r) {
6806               newp = fStartNew + (p - fStart)*2 + r;
6807               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6808             }
6809           } else if ((p >= fMax) && (p < fEnd)) {
6810             /* Old hybrid faces stay the same */
6811             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6812             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6813           } else if ((p >= cStart) && (p < cMax)) {
6814             /* Old interior cells add new cells and interior faces */
6815             for(r = 0; r < 4; ++r) {
6816               newp = cStartNew + (p - cStart)*4 + r;
6817               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6818             }
6819             for(r = 0; r < 3; ++r) {
6820               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6821               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6822             }
6823           } else if ((p >= cMax) && (p < cEnd)) {
6824             /* Old hybrid cells add new cells and hybrid face */
6825             for(r = 0; r < 2; ++r) {
6826               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6827               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6828             }
6829             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6830             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6831           }
6832           break;
6833         default:
6834           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6835         }
6836       }
6837       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6838       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6839     }
6840     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6841     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6842     if (0) {
6843       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6844       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6845       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6846     }
6847   }
6848   PetscFunctionReturn(0);
6849 }
6850 
6851 #undef __FUNCT__
6852 #define __FUNCT__ "DMPlexRefine_Uniform"
6853 /* This will only work for interpolated meshes */
6854 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6855 {
6856   DM              rdm;
6857   PetscInt       *depthSize;
6858   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
6859   PetscErrorCode  ierr;
6860 
6861   PetscFunctionBegin;
6862   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
6863   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6864   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6865   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6866   /* Calculate number of new points of each depth */
6867   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6868   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
6869   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6870   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6871   /* Step 1: Set chart */
6872   for(d = 0; d <= depth; ++d) {
6873     pEnd += depthSize[d];
6874   }
6875   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6876   /* Step 2: Set cone/support sizes */
6877   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6878   /* Step 3: Setup refined DM */
6879   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6880   /* Step 4: Set cones and supports */
6881   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6882   /* Step 5: Stratify */
6883   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6884   /* Step 6: Set coordinates for vertices */
6885   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6886   /* Step 7: Create pointSF */
6887   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6888   /* Step 8: Create labels */
6889   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6890   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6891 
6892   *dmRefined = rdm;
6893 #if 0
6894   DM_Plex *mesh = (DM_Plex *) dm->data;
6895   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
6896   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
6897 
6898   PetscFunctionBegin;
6899   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6900   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
6901   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6902   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6903   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
6904 
6905   /* Count number of new cells which are normal and extra */
6906   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
6907   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
6908   for(c = cStart; c < cEnd2; ++c) {
6909     PetscInt n;
6910     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
6911     newNumCellsNormal += n;
6912   }
6913   for(c = cEnd2; c < cEnd; ++c) {
6914     PetscInt n;
6915     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
6916     newNumCellsExtra += n;
6917   }
6918   newNumCells = newNumCellsNormal + newNumCellsExtra;
6919   /* Count number of new vertices which are normal and extra */
6920   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
6921   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
6922   for(c = cStart; c < cEnd; ++c) {
6923     PetscInt *closure = PETSC_NULL;
6924     PetscInt  closureSize, numCorners = 0, p;
6925 
6926     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6927     for(p = 0; p < closureSize*2; p += 2) {
6928       const PetscInt point = closure[p];
6929       if ((point >= vStart) && (point < vEnd)) {
6930         closure[numCorners++] = point;
6931       }
6932     }
6933     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
6934     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6935   }
6936   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
6937   for(c = cEnd2; c < cEnd; ++c) {
6938     PetscInt *closure = PETSC_NULL;
6939     PetscInt  closureSize, numCorners = 0, p;
6940 
6941     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6942     for(p = 0; p < closureSize*2; p += 2) {
6943       const PetscInt point = closure[p];
6944       if ((point >= vStart) && (point < vEnd)) {
6945         closure[numCorners++] = point;
6946       }
6947     }
6948     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
6949     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6950   } /* for */
6951   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
6952   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
6953 
6954 #if 1
6955   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
6956   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
6957   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
6958   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
6959   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
6960   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
6961   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
6962   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
6963   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
6964   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
6965   ierr = PetscSynchronizedFlush(comm);
6966 #endif
6967 
6968   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
6969   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
6970   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
6971   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
6972   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
6973   /* Set cone and support sizes for new normal cells */
6974   PetscInt newCell = 0;
6975   for(c = cStart; c < cEnd2; ++c) {
6976     PetscInt coneSize, n, i;
6977 
6978     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6979     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
6980     for(i = 0; i < n; ++i, ++newCell) {
6981       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
6982     }
6983 
6984     PetscInt *closure = PETSC_NULL;
6985     PetscInt  closureSize, numCorners = 0, p;
6986 
6987     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6988     for(p = 0; p < closureSize*2; p += 2) {
6989       const PetscInt point = closure[p];
6990       if ((point >= vStart) && (point < vEnd)) {
6991         closure[numCorners++] = point;
6992       }
6993     }
6994     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
6995     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6996   }
6997 
6998   /* Reset current new cell value and loop over censored cells. */
6999   curNewCell = _orderNewMesh->cellsCensored().min();
7000   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7001   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7002     /* Set new cone and support sizes */
7003     cV.clear();
7004     sieve->cone(*c_iter, cV);
7005     const point_type* cone = cV.getPoints();
7006     const int coneSize = cV.getSize();
7007 
7008     const point_type* newCells;
7009     int numNewCells = 0;
7010     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7011 
7012     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7013       newSieve->setConeSize(curNewCell, coneSize);
7014       for(int iVertex=0; iVertex < coneSize; ++iVertex) {
7015         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7016       } /* for */
7017     } /* for */
7018   } /* for */
7019   newSieve->allocate();
7020 
7021   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7022 
7023   /* Create refined cells in new sieve. */
7024   curNewCell = _orderNewMesh->cellsNormal().min();
7025   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7026   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7027     cV.clear();
7028     sieve->cone(*c_iter, cV);
7029     const point_type *cone = cV.getPoints();
7030     const int coneSize = cV.getSize();
7031 
7032     const point_type* newCells;
7033     int numNewCells = 0;
7034     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7035 
7036     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7037       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7038     } /* for */
7039   } /* for */
7040   curNewCell = _orderNewMesh->cellsCensored().min();
7041   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7042   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7043     cV.clear();
7044     sieve->cone(*c_iter, cV);
7045     const point_type *cone = cV.getPoints();
7046     const int coneSize = cV.getSize();
7047 
7048     const point_type* newCells;
7049     int numNewCells = 0;
7050     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7051 
7052     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7053       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7054     } /* for */
7055   } /* for */
7056   newSieve->symmetrize();
7057 
7058   /* Set coordinates in refined mesh. */
7059   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7060   assert(!coordinates.isNull());
7061   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7062   assert(!newCoordinates.isNull());
7063 
7064   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7065   assert(vertices->size() > 0);
7066   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7067   assert(spaceDim > 0);
7068   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7069 
7070   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7071   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7072     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7073   } /* for */
7074   newCoordinates->allocatePoint();
7075 
7076   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7077   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7078     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7079     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7080   } /* for */
7081   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7082   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7083     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7084     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7085   } /* for */
7086 
7087   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7088 
7089   /* Create sensored depth */
7090   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7091   assert(!censoredLabel.isNull());
7092 
7093   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7094 
7095   newSieve->roots(depthVisitor);
7096   while(depthVisitor.isModified()) {
7097     /* FIX: Avoid the copy here somehow by fixing the traversal */
7098     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7099 
7100     depthVisitor.clear();
7101     newSieve->support(modifiedPoints, depthVisitor);
7102   } /* while */
7103   /* Stratify refined mesh */
7104   /* Calculate new point SF */
7105   _calcNewOverlap(newMesh, mesh, refiner);
7106   /* Calculate new labels */
7107   _createLabels(newMesh, mesh, refiner);
7108 #endif
7109   PetscFunctionReturn(0);
7110 }
7111 
7112 #undef __FUNCT__
7113 #define __FUNCT__ "DMPlexSetRefinementUniform"
7114 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7115 {
7116   DM_Plex *mesh = (DM_Plex *) dm->data;
7117 
7118   PetscFunctionBegin;
7119   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7120   mesh->refinementUniform = refinementUniform;
7121   PetscFunctionReturn(0);
7122 }
7123 
7124 #undef __FUNCT__
7125 #define __FUNCT__ "DMPlexGetRefinementUniform"
7126 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7127 {
7128   DM_Plex *mesh = (DM_Plex *) dm->data;
7129 
7130   PetscFunctionBegin;
7131   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7132   PetscValidPointer(refinementUniform,  2);
7133   *refinementUniform = mesh->refinementUniform;
7134   PetscFunctionReturn(0);
7135 }
7136 
7137 #undef __FUNCT__
7138 #define __FUNCT__ "DMPlexSetRefinementLimit"
7139 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7140 {
7141   DM_Plex *mesh = (DM_Plex *) dm->data;
7142 
7143   PetscFunctionBegin;
7144   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7145   mesh->refinementLimit = refinementLimit;
7146   PetscFunctionReturn(0);
7147 }
7148 
7149 #undef __FUNCT__
7150 #define __FUNCT__ "DMPlexGetRefinementLimit"
7151 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7152 {
7153   DM_Plex *mesh = (DM_Plex *) dm->data;
7154 
7155   PetscFunctionBegin;
7156   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7157   PetscValidPointer(refinementLimit,  2);
7158   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7159   *refinementLimit = mesh->refinementLimit;
7160   PetscFunctionReturn(0);
7161 }
7162 
7163 #undef __FUNCT__
7164 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7165 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7166 {
7167   PetscInt       dim, cStart, coneSize, cMax;
7168   PetscErrorCode ierr;
7169 
7170   PetscFunctionBegin;
7171   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7172   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7173   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7174   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7175   switch(dim) {
7176   case 2:
7177     switch(coneSize) {
7178     case 3:
7179       if (cMax >= 0) {
7180         *cellRefiner = 3; /* Hybrid */
7181       } else {
7182         *cellRefiner = 1; /* Triangular */
7183       }
7184       break;
7185     case 4:
7186       if (cMax >= 0) {
7187         *cellRefiner = 4; /* Hybrid */
7188       } else {
7189         *cellRefiner = 2; /* Quadrilateral */
7190       }
7191       break;
7192     default:
7193       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7194     }
7195     break;
7196   default:
7197     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7198   }
7199   PetscFunctionReturn(0);
7200 }
7201 
7202 #undef __FUNCT__
7203 #define __FUNCT__ "DMRefine_Plex"
7204 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7205 {
7206   PetscReal      refinementLimit;
7207   PetscInt       dim, cStart, cEnd;
7208   char           genname[1024], *name = PETSC_NULL;
7209   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7210   PetscErrorCode ierr;
7211 
7212   PetscFunctionBegin;
7213   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7214   if (isUniform) {
7215     CellRefiner cellRefiner;
7216 
7217     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7218     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7219     PetscFunctionReturn(0);
7220   }
7221   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7222   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7223   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7224   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7225   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7226   if (flg) {name = genname;}
7227   if (name) {
7228     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7229     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7230     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7231   }
7232   switch(dim) {
7233   case 2:
7234     if (!name || isTriangle) {
7235 #ifdef PETSC_HAVE_TRIANGLE
7236       double  *maxVolumes;
7237       PetscInt c;
7238 
7239       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7240       for (c = 0; c < cEnd-cStart; ++c) {
7241         maxVolumes[c] = refinementLimit;
7242       }
7243       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7244 #else
7245       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7246 #endif
7247     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7248     break;
7249   case 3:
7250     if (!name || isCTetgen) {
7251 #ifdef PETSC_HAVE_CTETGEN
7252       PetscReal *maxVolumes;
7253       PetscInt   c;
7254 
7255       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7256       for (c = 0; c < cEnd-cStart; ++c) {
7257         maxVolumes[c] = refinementLimit;
7258       }
7259       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7260 #else
7261       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7262 #endif
7263     } else if (isTetgen) {
7264 #ifdef PETSC_HAVE_TETGEN
7265       double  *maxVolumes;
7266       PetscInt c;
7267 
7268       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7269       for (c = 0; c < cEnd-cStart; ++c) {
7270         maxVolumes[c] = refinementLimit;
7271       }
7272       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7273 #else
7274       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7275 #endif
7276     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7277     break;
7278   default:
7279     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7280   }
7281   PetscFunctionReturn(0);
7282 }
7283 
7284 #undef __FUNCT__
7285 #define __FUNCT__ "DMPlexGetDepth"
7286 /*@
7287   DMPlexGetDepth - get the number of strata
7288 
7289   Not Collective
7290 
7291   Input Parameters:
7292 . dm           - The DMPlex object
7293 
7294   Output Parameters:
7295 . depth - number of strata
7296 
7297   Level: developer
7298 
7299   Notes:
7300   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7301 
7302 .keywords: mesh, points
7303 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7304 @*/
7305 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7306 {
7307   PetscInt       d;
7308   PetscErrorCode ierr;
7309 
7310   PetscFunctionBegin;
7311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7312   PetscValidPointer(depth, 2);
7313   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7314   *depth = d-1;
7315   PetscFunctionReturn(0);
7316 }
7317 
7318 #undef __FUNCT__
7319 #define __FUNCT__ "DMPlexGetDepthStratum"
7320 /*@
7321   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7322 
7323   Not Collective
7324 
7325   Input Parameters:
7326 + dm           - The DMPlex object
7327 - stratumValue - The requested depth
7328 
7329   Output Parameters:
7330 + start - The first point at this depth
7331 - end   - One beyond the last point at this depth
7332 
7333   Level: developer
7334 
7335 .keywords: mesh, points
7336 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7337 @*/
7338 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7339 {
7340   DM_Plex    *mesh = (DM_Plex *) dm->data;
7341   DMLabel        next = mesh->labels;
7342   PetscBool      flg  = PETSC_FALSE;
7343   PetscInt       depth;
7344   PetscErrorCode ierr;
7345 
7346   PetscFunctionBegin;
7347   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7348   if (stratumValue < 0) {
7349     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7350     PetscFunctionReturn(0);
7351   } else {
7352     PetscInt pStart, pEnd;
7353 
7354     if (start) {*start = 0;}
7355     if (end)   {*end   = 0;}
7356     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7357     if (pStart == pEnd) {PetscFunctionReturn(0);}
7358   }
7359   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7360   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7361   /* We should have a generic GetLabel() and a Label class */
7362   while(next) {
7363     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7364     if (flg) break;
7365     next = next->next;
7366   }
7367   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7368   depth = stratumValue;
7369   if ((depth < 0) || (depth >= next->numStrata)) {
7370     if (start) {*start = 0;}
7371     if (end)   {*end   = 0;}
7372   } else {
7373     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7374     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7375   }
7376   PetscFunctionReturn(0);
7377 }
7378 
7379 #undef __FUNCT__
7380 #define __FUNCT__ "DMPlexGetHeightStratum"
7381 /*@
7382   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7383 
7384   Not Collective
7385 
7386   Input Parameters:
7387 + dm           - The DMPlex object
7388 - stratumValue - The requested height
7389 
7390   Output Parameters:
7391 + start - The first point at this height
7392 - end   - One beyond the last point at this height
7393 
7394   Level: developer
7395 
7396 .keywords: mesh, points
7397 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7398 @*/
7399 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7400 {
7401   DM_Plex        *mesh = (DM_Plex *) dm->data;
7402   DMLabel        next = mesh->labels;
7403   PetscBool      flg  = PETSC_FALSE;
7404   PetscInt       depth;
7405   PetscErrorCode ierr;
7406 
7407   PetscFunctionBegin;
7408   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7409   if (stratumValue < 0) {
7410     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7411   } else {
7412     PetscInt pStart, pEnd;
7413 
7414     if (start) {*start = 0;}
7415     if (end)   {*end   = 0;}
7416     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7417     if (pStart == pEnd) {PetscFunctionReturn(0);}
7418   }
7419   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7420   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7421   /* We should have a generic GetLabel() and a Label class */
7422   while(next) {
7423     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7424     if (flg) break;
7425     next = next->next;
7426   }
7427   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7428   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7429   if ((depth < 0) || (depth >= next->numStrata)) {
7430     if (start) {*start = 0;}
7431     if (end)   {*end   = 0;}
7432   } else {
7433     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7434     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7435   }
7436   PetscFunctionReturn(0);
7437 }
7438 
7439 #undef __FUNCT__
7440 #define __FUNCT__ "DMPlexCreateSectionInitial"
7441 /* Set the number of dof on each point and separate by fields */
7442 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7443 {
7444   PetscInt      *numDofTot;
7445   PetscInt       pStart = 0, pEnd = 0;
7446   PetscInt       p, d, f;
7447   PetscErrorCode ierr;
7448 
7449   PetscFunctionBegin;
7450   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7451   for(d = 0; d <= dim; ++d) {
7452     numDofTot[d] = 0;
7453     for(f = 0; f < numFields; ++f) {
7454       numDofTot[d] += numDof[f*(dim+1)+d];
7455     }
7456   }
7457   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7458   if (numFields > 0) {
7459     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7460     if (numComp) {
7461       for(f = 0; f < numFields; ++f) {
7462         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7463       }
7464     }
7465   }
7466   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7467   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7468   for(d = 0; d <= dim; ++d) {
7469     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7470     for(p = pStart; p < pEnd; ++p) {
7471       for(f = 0; f < numFields; ++f) {
7472         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7473       }
7474       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7475     }
7476   }
7477   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7478   PetscFunctionReturn(0);
7479 }
7480 
7481 #undef __FUNCT__
7482 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7483 /* Set the number of dof on each point and separate by fields
7484    If constDof is PETSC_DETERMINE, constrain every dof on the point
7485 */
7486 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7487 {
7488   PetscInt       numFields;
7489   PetscInt       bc;
7490   PetscErrorCode ierr;
7491 
7492   PetscFunctionBegin;
7493   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7494   for (bc = 0; bc < numBC; ++bc) {
7495     PetscInt        field = 0;
7496     const PetscInt *idx;
7497     PetscInt        n, i;
7498 
7499     if (numFields) {field = bcField[bc];}
7500     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7501     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7502     for (i = 0; i < n; ++i) {
7503       const PetscInt p = idx[i];
7504       PetscInt       numConst = constDof;
7505 
7506       /* Constrain every dof on the point */
7507       if (numConst < 0) {
7508         if (numFields) {
7509           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7510         } else {
7511           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7512         }
7513       }
7514       if (numFields) {
7515         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7516       }
7517       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7518     }
7519     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7520   }
7521   PetscFunctionReturn(0);
7522 }
7523 
7524 #undef __FUNCT__
7525 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7526 /* Set the constrained indices on each point and separate by fields */
7527 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7528 {
7529   PetscInt      *maxConstraints;
7530   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7531   PetscErrorCode ierr;
7532 
7533   PetscFunctionBegin;
7534   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7535   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7536   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7537   for(f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
7538   for(p = pStart; p < pEnd; ++p) {
7539     PetscInt cdof;
7540 
7541     if (numFields) {
7542       for(f = 0; f < numFields; ++f) {
7543         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7544         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7545       }
7546     } else {
7547       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7548       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7549     }
7550   }
7551   for (f = 0; f < numFields; ++f) {
7552     maxConstraints[numFields] += maxConstraints[f];
7553   }
7554   if (maxConstraints[numFields]) {
7555     PetscInt *indices;
7556 
7557     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7558     for (p = pStart; p < pEnd; ++p) {
7559       PetscInt cdof, d;
7560 
7561       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7562       if (cdof) {
7563         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7564         if (numFields) {
7565           PetscInt numConst = 0, foff = 0;
7566 
7567           for (f = 0; f < numFields; ++f) {
7568             PetscInt cfdof, fdof;
7569 
7570             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7571             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7572             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7573             for(d = 0; d < cfdof; ++d) {
7574               indices[numConst+d] = d;
7575             }
7576             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7577             for(d = 0; d < cfdof; ++d) {
7578               indices[numConst+d] += foff;
7579             }
7580             numConst += cfdof;
7581             foff     += fdof;
7582           }
7583           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7584         } else {
7585           for (d = 0; d < cdof; ++d) {
7586             indices[d] = d;
7587           }
7588         }
7589         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7590       }
7591     }
7592     ierr = PetscFree(indices);CHKERRQ(ierr);
7593   }
7594   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7595   PetscFunctionReturn(0);
7596 }
7597 
7598 #undef __FUNCT__
7599 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7600 /* Set the constrained field indices on each point */
7601 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7602 {
7603   const PetscInt *points, *indices;
7604   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7605   PetscErrorCode  ierr;
7606 
7607   PetscFunctionBegin;
7608   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7609   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7610 
7611   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7612   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7613   if (!constraintIndices) {
7614     PetscInt *idx, i;
7615 
7616     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7617     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7618     for(i = 0; i < maxDof; ++i) {idx[i] = i;}
7619     for(p = 0; p < numPoints; ++p) {
7620       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7621     }
7622     ierr = PetscFree(idx);CHKERRQ(ierr);
7623   } else {
7624     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7625     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7626     for(p = 0; p < numPoints; ++p) {
7627       PetscInt fcdof;
7628 
7629       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7630       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);
7631       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7632     }
7633     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7634   }
7635   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7636   PetscFunctionReturn(0);
7637 }
7638 
7639 #undef __FUNCT__
7640 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7641 /* Set the constrained indices on each point and separate by fields */
7642 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7643 {
7644   PetscInt      *indices;
7645   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7646   PetscErrorCode ierr;
7647 
7648   PetscFunctionBegin;
7649   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7650   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7651   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7652   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7653   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7654   for (p = pStart; p < pEnd; ++p) {
7655     PetscInt cdof, d;
7656 
7657     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7658     if (cdof) {
7659       PetscInt numConst = 0, foff = 0;
7660 
7661       for (f = 0; f < numFields; ++f) {
7662         const PetscInt *fcind;
7663         PetscInt        fdof, fcdof;
7664 
7665         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7666         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7667         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7668         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7669         for(d = 0; d < fcdof; ++d) {
7670           indices[numConst+d] = fcind[d]+foff;
7671         }
7672         foff     += fdof;
7673         numConst += fcdof;
7674       }
7675       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7676       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7677     }
7678   }
7679   ierr = PetscFree(indices);CHKERRQ(ierr);
7680   PetscFunctionReturn(0);
7681 }
7682 
7683 #undef __FUNCT__
7684 #define __FUNCT__ "DMPlexCreateSection"
7685 /*@C
7686   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7687 
7688   Not Collective
7689 
7690   Input Parameters:
7691 + dm        - The DMPlex object
7692 . dim       - The spatial dimension of the problem
7693 . numFields - The number of fields in the problem
7694 . numComp   - An array of size numFields that holds the number of components for each field
7695 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7696 . numBC     - The number of boundary conditions
7697 . bcField   - An array of size numBC giving the field number for each boundry condition
7698 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7699 
7700   Output Parameter:
7701 . section - The PetscSection object
7702 
7703   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
7704   nubmer of dof for field 0 on each edge.
7705 
7706   Level: developer
7707 
7708 .keywords: mesh, elements
7709 .seealso: DMPlexCreate(), PetscSectionCreate()
7710 @*/
7711 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
7712 {
7713   PetscErrorCode ierr;
7714 
7715   PetscFunctionBegin;
7716   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7717   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7718   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7719   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7720   {
7721     PetscBool view = PETSC_FALSE;
7722 
7723     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7724     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7725   }
7726   PetscFunctionReturn(0);
7727 }
7728 
7729 #undef __FUNCT__
7730 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7731 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
7732 {
7733   PetscSection   section;
7734   PetscErrorCode ierr;
7735 
7736   PetscFunctionBegin;
7737   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7738   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
7739   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7740   PetscFunctionReturn(0);
7741 }
7742 
7743 #undef __FUNCT__
7744 #define __FUNCT__ "DMPlexGetCoordinateSection"
7745 /*@
7746   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7747 
7748   Not Collective
7749 
7750   Input Parameter:
7751 . dm - The DMPlex object
7752 
7753   Output Parameter:
7754 . section - The PetscSection object
7755 
7756   Level: intermediate
7757 
7758 .keywords: mesh, coordinates
7759 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7760 @*/
7761 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
7762 {
7763   DM             cdm;
7764   PetscErrorCode ierr;
7765 
7766   PetscFunctionBegin;
7767   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7768   PetscValidPointer(section, 2);
7769   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7770   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7771   PetscFunctionReturn(0);
7772 }
7773 
7774 #undef __FUNCT__
7775 #define __FUNCT__ "DMPlexSetCoordinateSection"
7776 /*@
7777   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7778 
7779   Not Collective
7780 
7781   Input Parameters:
7782 + dm      - The DMPlex object
7783 - section - The PetscSection object
7784 
7785   Level: intermediate
7786 
7787 .keywords: mesh, coordinates
7788 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7789 @*/
7790 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
7791 {
7792   DM             cdm;
7793   PetscErrorCode ierr;
7794 
7795   PetscFunctionBegin;
7796   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7797   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7798   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7799   PetscFunctionReturn(0);
7800 }
7801 
7802 #undef __FUNCT__
7803 #define __FUNCT__ "DMPlexGetConeSection"
7804 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
7805 {
7806   DM_Plex *mesh = (DM_Plex *) dm->data;
7807 
7808   PetscFunctionBegin;
7809   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7810   if (section) *section = mesh->coneSection;
7811   PetscFunctionReturn(0);
7812 }
7813 
7814 #undef __FUNCT__
7815 #define __FUNCT__ "DMPlexGetCones"
7816 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
7817 {
7818   DM_Plex *mesh = (DM_Plex *) dm->data;
7819 
7820   PetscFunctionBegin;
7821   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7822   if (cones) *cones = mesh->cones;
7823   PetscFunctionReturn(0);
7824 }
7825 
7826 #undef __FUNCT__
7827 #define __FUNCT__ "DMPlexGetConeOrientations"
7828 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
7829 {
7830   DM_Plex *mesh = (DM_Plex *) dm->data;
7831 
7832   PetscFunctionBegin;
7833   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7834   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7835   PetscFunctionReturn(0);
7836 }
7837 
7838 #undef __FUNCT__
7839 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7840 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7841 {
7842   const PetscInt embedDim = 2;
7843   PetscReal      x = PetscRealPart(point[0]);
7844   PetscReal      y = PetscRealPart(point[1]);
7845   PetscReal      v0[2], J[4], invJ[4], detJ;
7846   PetscReal      xi, eta;
7847   PetscErrorCode ierr;
7848 
7849   PetscFunctionBegin;
7850   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7851   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7852   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7853 
7854   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
7855     *cell = c;
7856   } else {
7857     *cell = -1;
7858   }
7859   PetscFunctionReturn(0);
7860 }
7861 
7862 #undef __FUNCT__
7863 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7864 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7865 {
7866   PetscSection       coordSection;
7867   Vec                coordsLocal;
7868   const PetscScalar *coords;
7869   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7870   PetscReal          x         = PetscRealPart(point[0]);
7871   PetscReal          y         = PetscRealPart(point[1]);
7872   PetscInt           crossings = 0, f;
7873   PetscErrorCode     ierr;
7874 
7875   PetscFunctionBegin;
7876   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7877   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7878   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7879   for(f = 0; f < 4; ++f) {
7880     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7881     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7882     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7883     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7884     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7885     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7886     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7887     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7888     if ((cond1 || cond2)  && above) ++crossings;
7889   }
7890   if (crossings % 2) {
7891     *cell = c;
7892   } else {
7893     *cell = -1;
7894   }
7895   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7896   PetscFunctionReturn(0);
7897 }
7898 
7899 #undef __FUNCT__
7900 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7901 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7902 {
7903   const PetscInt embedDim = 3;
7904   PetscReal      v0[3], J[9], invJ[9], detJ;
7905   PetscReal      x = PetscRealPart(point[0]);
7906   PetscReal      y = PetscRealPart(point[1]);
7907   PetscReal      z = PetscRealPart(point[2]);
7908   PetscReal      xi, eta, zeta;
7909   PetscErrorCode ierr;
7910 
7911   PetscFunctionBegin;
7912   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7913   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
7914   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
7915   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
7916 
7917   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
7918     *cell = c;
7919   } else {
7920     *cell = -1;
7921   }
7922   PetscFunctionReturn(0);
7923 }
7924 
7925 #undef __FUNCT__
7926 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7927 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7928 {
7929   PetscSection       coordSection;
7930   Vec                coordsLocal;
7931   const PetscScalar *coords;
7932   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7933                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7934   PetscBool          found     = PETSC_TRUE;
7935   PetscInt           f;
7936   PetscErrorCode     ierr;
7937 
7938   PetscFunctionBegin;
7939   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7940   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7941   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7942   for(f = 0; f < 6; ++f) {
7943     /* Check the point is under plane */
7944     /*   Get face normal */
7945     PetscReal v_i[3]    = {PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]),
7946                            PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]),
7947                            PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2])};
7948     PetscReal v_j[3]    = {PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]),
7949                            PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]),
7950                            PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2])};
7951     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]};
7952     PetscReal pp[3]     = {PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]),
7953                            PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]),
7954                            PetscRealPart(coords[faces[f*4+0]*3+2] - point[2])};
7955     PetscReal dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7956     /* Check that projected point is in face (2D location problem) */
7957     if (dot < 0.0) {
7958       found = PETSC_FALSE;
7959       break;
7960     }
7961   }
7962   if (found) {
7963     *cell = c;
7964   } else {
7965     *cell = -1;
7966   }
7967   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7968   PetscFunctionReturn(0);
7969 }
7970 
7971 #undef __FUNCT__
7972 #define __FUNCT__ "DMLocatePoints_Plex"
7973 /*
7974  Need to implement using the guess
7975 */
7976 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7977 {
7978   PetscInt       cell = -1/*, guess = -1*/;
7979   PetscInt       bs, numPoints, p;
7980   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7981   PetscInt      *cells;
7982   PetscScalar   *a;
7983   PetscErrorCode ierr;
7984 
7985   PetscFunctionBegin;
7986   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7987   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7988   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7989   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
7990   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7991   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7992   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7993   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);
7994   numPoints /= bs;
7995   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7996   for(p = 0; p < numPoints; ++p) {
7997     const PetscScalar *point = &a[p*bs];
7998 
7999     switch(dim) {
8000     case 2:
8001       for(c = cStart; c < cEnd; ++c) {
8002         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8003         switch(coneSize) {
8004         case 3:
8005           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8006           break;
8007         case 4:
8008           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8009           break;
8010         default:
8011           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8012         }
8013         if (cell >= 0) break;
8014       }
8015       break;
8016     case 3:
8017       for(c = cStart; c < cEnd; ++c) {
8018         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8019         switch(coneSize) {
8020         case 4:
8021           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8022           break;
8023         case 8:
8024           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8025           break;
8026         default:
8027           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8028         }
8029         if (cell >= 0) break;
8030       }
8031       break;
8032     default:
8033       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8034     }
8035     cells[p] = cell;
8036   }
8037   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8038   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8039   PetscFunctionReturn(0);
8040 }
8041 
8042 /******************************** FEM Support **********************************/
8043 
8044 #undef __FUNCT__
8045 #define __FUNCT__ "DMPlexVecGetClosure"
8046 /*@C
8047   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8048 
8049   Not collective
8050 
8051   Input Parameters:
8052 + dm - The DM
8053 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8054 . v - The local vector
8055 - point - The sieve point in the DM
8056 
8057   Output Parameters:
8058 + csize - The number of values in the closure, or PETSC_NULL
8059 - values - The array of values, which is a borrowed array and should not be freed
8060 
8061   Level: intermediate
8062 
8063 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8064 @*/
8065 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8066 {
8067   PetscScalar    *array, *vArray;
8068   PetscInt       *points = PETSC_NULL;
8069   PetscInt        offsets[32];
8070   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
8071   PetscErrorCode  ierr;
8072 
8073   PetscFunctionBegin;
8074   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8075   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8076   if (!section) {
8077     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8078   }
8079   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8080   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8081   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8082   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8083   /* Compress out points not in the section */
8084   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8085   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8086     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8087       points[q*2]   = points[p];
8088       points[q*2+1] = points[p+1];
8089       ++q;
8090     }
8091   }
8092   numPoints = q;
8093   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8094     PetscInt dof, fdof;
8095 
8096     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8097     for (f = 0; f < numFields; ++f) {
8098       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8099       offsets[f+1] += fdof;
8100     }
8101     size += dof;
8102   }
8103   for (f = 1; f < numFields; ++f) {
8104     offsets[f+1] += offsets[f];
8105   }
8106   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8107   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8108   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8109   for (p = 0; p < numPoints*2; p += 2) {
8110     PetscInt     o = points[p+1];
8111     PetscInt     dof, off, d;
8112     PetscScalar *varr;
8113 
8114     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8115     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8116     varr = &vArray[off];
8117     if (numFields) {
8118       PetscInt fdof, foff, fcomp, f, c;
8119 
8120       for (f = 0, foff = 0; f < numFields; ++f) {
8121         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8122         if (o >= 0) {
8123           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8124             array[offsets[f]] = varr[foff+d];
8125           }
8126         } else {
8127           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8128           for (d = fdof/fcomp-1; d >= 0; --d) {
8129             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8130               array[offsets[f]] = varr[foff+d*fcomp+c];
8131             }
8132           }
8133         }
8134         foff += fdof;
8135       }
8136     } else {
8137       if (o >= 0) {
8138         for (d = 0; d < dof; ++d, ++offsets[0]) {
8139           array[offsets[0]] = varr[d];
8140         }
8141       } else {
8142         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8143           array[offsets[0]] = varr[d];
8144         }
8145       }
8146     }
8147   }
8148   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8149   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8150   if (csize) *csize = size;
8151   *values = array;
8152   PetscFunctionReturn(0);
8153 }
8154 
8155 #undef __FUNCT__
8156 #define __FUNCT__ "DMPlexVecRestoreClosure"
8157 /*@C
8158   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8159 
8160   Not collective
8161 
8162   Input Parameters:
8163 + dm - The DM
8164 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8165 . v - The local vector
8166 . point - The sieve point in the DM
8167 . csize - The number of values in the closure, or PETSC_NULL
8168 - values - The array of values, which is a borrowed array and should not be freed
8169 
8170   Level: intermediate
8171 
8172 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8173 @*/
8174 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8175 {
8176   PetscInt        size = 0;
8177   PetscErrorCode  ierr;
8178 
8179   PetscFunctionBegin;
8180   /* Should work without recalculating size */
8181   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
8182   PetscFunctionReturn(0);
8183 }
8184 
8185 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8186 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8187 
8188 #undef __FUNCT__
8189 #define __FUNCT__ "updatePoint_private"
8190 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8191 {
8192   PetscInt        cdof;  /* The number of constraints on this point */
8193   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8194   PetscScalar    *a;
8195   PetscInt        off, cind = 0, k;
8196   PetscErrorCode  ierr;
8197 
8198   PetscFunctionBegin;
8199   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8200   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8201   a    = &array[off];
8202   if (!cdof || setBC) {
8203     if (orientation >= 0) {
8204       for (k = 0; k < dof; ++k) {
8205         fuse(&a[k], values[k]);
8206       }
8207     } else {
8208       for (k = 0; k < dof; ++k) {
8209         fuse(&a[k], values[dof-k-1]);
8210       }
8211     }
8212   } else {
8213     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8214     if (orientation >= 0) {
8215       for (k = 0; k < dof; ++k) {
8216         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8217         fuse(&a[k], values[k]);
8218       }
8219     } else {
8220       for (k = 0; k < dof; ++k) {
8221         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8222         fuse(&a[k], values[dof-k-1]);
8223       }
8224     }
8225   }
8226   PetscFunctionReturn(0);
8227 }
8228 
8229 #undef __FUNCT__
8230 #define __FUNCT__ "updatePointFields_private"
8231 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8232 {
8233   PetscScalar   *a;
8234   PetscInt       numFields, off, foff, f;
8235   PetscErrorCode ierr;
8236 
8237   PetscFunctionBegin;
8238   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8239   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8240   a    = &array[off];
8241   for (f = 0, foff = 0; f < numFields; ++f) {
8242     PetscInt        fdof, fcomp, fcdof;
8243     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8244     PetscInt        cind = 0, k, c;
8245 
8246     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8247     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8248     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8249     if (!fcdof || setBC) {
8250       if (orientation >= 0) {
8251         for (k = 0; k < fdof; ++k) {
8252           fuse(&a[foff+k], values[foffs[f]+k]);
8253         }
8254       } else {
8255         for (k = fdof/fcomp-1; k >= 0; --k) {
8256           for (c = 0; c < fcomp; ++c) {
8257             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8258           }
8259         }
8260       }
8261     } else {
8262       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8263       if (orientation >= 0) {
8264         for (k = 0; k < fdof; ++k) {
8265           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8266           fuse(&a[foff+k], values[foffs[f]+k]);
8267         }
8268       } else {
8269         for (k = fdof/fcomp-1; k >= 0; --k) {
8270           for (c = 0; c < fcomp; ++c) {
8271             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8272             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8273           }
8274         }
8275       }
8276     }
8277     foff     += fdof;
8278     foffs[f] += fdof;
8279   }
8280   PetscFunctionReturn(0);
8281 }
8282 
8283 #undef __FUNCT__
8284 #define __FUNCT__ "DMPlexVecSetClosure"
8285 /*@C
8286   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8287 
8288   Not collective
8289 
8290   Input Parameters:
8291 + dm - The DM
8292 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8293 . v - The local vector
8294 . point - The sieve point in the DM
8295 . values - The array of values, which is a borrowed array and should not be freed
8296 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8297 
8298   Level: intermediate
8299 
8300 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8301 @*/
8302 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8303 {
8304   PetscScalar    *array;
8305   PetscInt       *points = PETSC_NULL;
8306   PetscInt        offsets[32];
8307   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8308   PetscErrorCode  ierr;
8309 
8310   PetscFunctionBegin;
8311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8312   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8313   if (!section) {
8314     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8315   }
8316   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8317   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8318   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8319   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8320   /* Compress out points not in the section */
8321   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8322   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8323     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8324       points[q*2]   = points[p];
8325       points[q*2+1] = points[p+1];
8326       ++q;
8327     }
8328   }
8329   numPoints = q;
8330   for (p = 0; p < numPoints*2; p += 2) {
8331     PetscInt fdof;
8332 
8333     for (f = 0; f < numFields; ++f) {
8334       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8335       offsets[f+1] += fdof;
8336     }
8337   }
8338   for (f = 1; f < numFields; ++f) {
8339     offsets[f+1] += offsets[f];
8340   }
8341   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8342   if (numFields) {
8343     switch(mode) {
8344     case INSERT_VALUES:
8345       for (p = 0; p < numPoints*2; p += 2) {
8346         PetscInt o = points[p+1];
8347         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8348       } break;
8349     case INSERT_ALL_VALUES:
8350       for (p = 0; p < numPoints*2; p += 2) {
8351         PetscInt o = points[p+1];
8352         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8353       } break;
8354     case ADD_VALUES:
8355       for (p = 0; p < numPoints*2; p += 2) {
8356         PetscInt o = points[p+1];
8357         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8358       } break;
8359     case ADD_ALL_VALUES:
8360       for (p = 0; p < numPoints*2; p += 2) {
8361         PetscInt o = points[p+1];
8362         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8363       } break;
8364     default:
8365       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8366     }
8367   } else {
8368     switch(mode) {
8369     case INSERT_VALUES:
8370       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8371         PetscInt o = points[p+1];
8372         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8373         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8374       } break;
8375     case INSERT_ALL_VALUES:
8376       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8377         PetscInt o = points[p+1];
8378         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8379         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8380       } break;
8381     case ADD_VALUES:
8382       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8383         PetscInt o = points[p+1];
8384         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8385         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8386       } break;
8387     case ADD_ALL_VALUES:
8388       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8389         PetscInt o = points[p+1];
8390         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8391         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8392       } break;
8393     default:
8394       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8395     }
8396   }
8397   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8398   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8399   PetscFunctionReturn(0);
8400 }
8401 
8402 #undef __FUNCT__
8403 #define __FUNCT__ "DMPlexPrintMatSetValues"
8404 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8405 {
8406   PetscMPIInt    rank;
8407   PetscInt       i, j;
8408   PetscErrorCode ierr;
8409 
8410   PetscFunctionBegin;
8411   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8412   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8413   for (i = 0; i < numIndices; i++) {
8414     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8415   }
8416   for (i = 0; i < numIndices; i++) {
8417     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8418     for (j = 0; j < numIndices; j++) {
8419 #ifdef PETSC_USE_COMPLEX
8420       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8421 #else
8422       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8423 #endif
8424     }
8425     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8426   }
8427   PetscFunctionReturn(0);
8428 }
8429 
8430 #undef __FUNCT__
8431 #define __FUNCT__ "indicesPoint_private"
8432 /* . off - The global offset of this point */
8433 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8434 {
8435   PetscInt        cdof;  /* The number of constraints on this point */
8436   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8437   PetscInt        cind = 0, k;
8438   PetscErrorCode  ierr;
8439 
8440   PetscFunctionBegin;
8441   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8442   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8443   if (!cdof || setBC) {
8444     if (orientation >= 0) {
8445       for (k = 0; k < dof; ++k) {
8446         indices[k] = off+k;
8447       }
8448     } else {
8449       for (k = 0; k < dof; ++k) {
8450         indices[dof-k-1] = off+k;
8451       }
8452     }
8453   } else {
8454     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8455     if (orientation >= 0) {
8456       for (k = 0; k < dof; ++k) {
8457         if ((cind < cdof) && (k == cdofs[cind])) {
8458           /* Insert check for returning constrained indices */
8459           indices[k] = -(off+k+1);
8460           ++cind;
8461         } else {
8462           indices[k] = off+k-cind;
8463         }
8464       }
8465     } else {
8466       for (k = 0; k < dof; ++k) {
8467         if ((cind < cdof) && (k == cdofs[cind])) {
8468           /* Insert check for returning constrained indices */
8469           indices[dof-k-1] = -(off+k+1);
8470           ++cind;
8471         } else {
8472           indices[dof-k-1] = off+k-cind;
8473         }
8474       }
8475     }
8476   }
8477   PetscFunctionReturn(0);
8478 }
8479 
8480 #undef __FUNCT__
8481 #define __FUNCT__ "indicesPointFields_private"
8482 /* . off - The global offset of this point */
8483 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8484 {
8485   PetscInt       numFields, foff, f;
8486   PetscErrorCode ierr;
8487 
8488   PetscFunctionBegin;
8489   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8490   for (f = 0, foff = 0; f < numFields; ++f) {
8491     PetscInt        fdof, fcomp, cfdof;
8492     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8493     PetscInt        cind = 0, k, c;
8494 
8495     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8496     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8497     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8498     if (!cfdof || setBC) {
8499       if (orientation >= 0) {
8500         for (k = 0; k < fdof; ++k) {
8501           indices[foffs[f]+k] = off+foff+k;
8502         }
8503       } else {
8504         for (k = fdof/fcomp-1; k >= 0; --k) {
8505           for (c = 0; c < fcomp; ++c) {
8506             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8507           }
8508         }
8509       }
8510     } else {
8511       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8512       if (orientation >= 0) {
8513         for (k = 0; k < fdof; ++k) {
8514           if ((cind < cfdof) && (k == fcdofs[cind])) {
8515             indices[foffs[f]+k] = -(off+foff+k+1);
8516             ++cind;
8517           } else {
8518             indices[foffs[f]+k] = off+foff+k-cind;
8519           }
8520         }
8521       } else {
8522         for (k = fdof/fcomp-1; k >= 0; --k) {
8523           for (c = 0; c < fcomp; ++c) {
8524             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8525               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8526               ++cind;
8527             } else {
8528               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8529             }
8530           }
8531         }
8532       }
8533     }
8534     foff     += fdof - cfdof;
8535     foffs[f] += fdof;
8536   }
8537   PetscFunctionReturn(0);
8538 }
8539 
8540 #undef __FUNCT__
8541 #define __FUNCT__ "DMPlexMatSetClosure"
8542 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8543 {
8544   DM_Plex     *mesh   = (DM_Plex *) dm->data;
8545   PetscInt       *points = PETSC_NULL;
8546   PetscInt       *indices;
8547   PetscInt        offsets[32];
8548   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8549   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8550   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8551   PetscErrorCode  ierr;
8552 
8553   PetscFunctionBegin;
8554   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8555   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8556   if (useDefault) {
8557     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8558   }
8559   if (useGlobalDefault) {
8560     if (useDefault) {
8561       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8562     } else {
8563       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8564     }
8565   }
8566   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8567   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8568   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8569   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8570   /* Compress out points not in the section */
8571   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8572   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8573     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8574       points[q*2]   = points[p];
8575       points[q*2+1] = points[p+1];
8576       ++q;
8577     }
8578   }
8579   numPoints = q;
8580   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8581     PetscInt fdof;
8582 
8583     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8584     for (f = 0; f < numFields; ++f) {
8585       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8586       offsets[f+1] += fdof;
8587     }
8588     numIndices += dof;
8589   }
8590   for (f = 1; f < numFields; ++f) {
8591     offsets[f+1] += offsets[f];
8592   }
8593   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8594   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8595   if (numFields) {
8596     for (p = 0; p < numPoints*2; p += 2) {
8597       PetscInt o = points[p+1];
8598       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8599       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8600     }
8601   } else {
8602     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8603       PetscInt o = points[p+1];
8604       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8605       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8606     }
8607   }
8608   if (useGlobalDefault && !useDefault) {
8609     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8610   }
8611   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8612   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8613   if (ierr) {
8614     PetscMPIInt    rank;
8615     PetscErrorCode ierr2;
8616 
8617     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8618     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8619     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8620     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8621     CHKERRQ(ierr);
8622   }
8623   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8624   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8625   PetscFunctionReturn(0);
8626 }
8627 
8628 #undef __FUNCT__
8629 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8630 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8631 {
8632   PetscSection       coordSection;
8633   Vec                coordinates;
8634   const PetscScalar *coords;
8635   const PetscInt     dim = 2;
8636   PetscInt           d, f;
8637   PetscErrorCode     ierr;
8638 
8639   PetscFunctionBegin;
8640   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8641   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8642   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8643   if (v0) {
8644     for (d = 0; d < dim; d++) {
8645       v0[d] = PetscRealPart(coords[d]);
8646     }
8647   }
8648   if (J) {
8649     for (d = 0; d < dim; d++) {
8650       for (f = 0; f < dim; f++) {
8651         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8652       }
8653     }
8654     *detJ = J[0]*J[3] - J[1]*J[2];
8655 #if 0
8656     if (detJ < 0.0) {
8657       const PetscReal xLength = mesh->periodicity[0];
8658 
8659       if (xLength != 0.0) {
8660         PetscReal v0x = coords[0*dim+0];
8661 
8662         if (v0x == 0.0) {
8663           v0x = v0[0] = xLength;
8664         }
8665         for (f = 0; f < dim; f++) {
8666           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8667 
8668           J[0*dim+f] = 0.5*(px - v0x);
8669         }
8670       }
8671       detJ = J[0]*J[3] - J[1]*J[2];
8672     }
8673 #endif
8674     PetscLogFlops(8.0 + 3.0);
8675   }
8676   if (invJ) {
8677     const PetscReal invDet = 1.0/(*detJ);
8678 
8679     invJ[0] =  invDet*J[3];
8680     invJ[1] = -invDet*J[1];
8681     invJ[2] = -invDet*J[2];
8682     invJ[3] =  invDet*J[0];
8683     PetscLogFlops(5.0);
8684   }
8685   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8686   PetscFunctionReturn(0);
8687 }
8688 
8689 #undef __FUNCT__
8690 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8691 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8692 {
8693   PetscSection       coordSection;
8694   Vec                coordinates;
8695   const PetscScalar *coords;
8696   const PetscInt     dim = 2;
8697   PetscInt           d, f;
8698   PetscErrorCode     ierr;
8699 
8700   PetscFunctionBegin;
8701   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8702   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8703   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8704   if (v0) {
8705     for (d = 0; d < dim; d++) {
8706       v0[d] = PetscRealPart(coords[d]);
8707     }
8708   }
8709   if (J) {
8710     for (d = 0; d < dim; d++) {
8711       for (f = 0; f < dim; f++) {
8712         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8713       }
8714     }
8715     *detJ = J[0]*J[3] - J[1]*J[2];
8716     PetscLogFlops(8.0 + 3.0);
8717   }
8718   if (invJ) {
8719     const PetscReal invDet = 1.0/(*detJ);
8720 
8721     invJ[0] =  invDet*J[3];
8722     invJ[1] = -invDet*J[1];
8723     invJ[2] = -invDet*J[2];
8724     invJ[3] =  invDet*J[0];
8725     PetscLogFlops(5.0);
8726   }
8727   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8728   PetscFunctionReturn(0);
8729 }
8730 
8731 #undef __FUNCT__
8732 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8733 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8734 {
8735   PetscSection       coordSection;
8736   Vec                coordinates;
8737   const PetscScalar *coords;
8738   const PetscInt     dim = 3;
8739   PetscInt           d, f;
8740   PetscErrorCode     ierr;
8741 
8742   PetscFunctionBegin;
8743   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8744   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8745   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8746   if (v0) {
8747     for (d = 0; d < dim; d++) {
8748       v0[d] = PetscRealPart(coords[d]);
8749     }
8750   }
8751   if (J) {
8752     for (d = 0; d < dim; d++) {
8753       for (f = 0; f < dim; f++) {
8754         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8755       }
8756     }
8757     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8758     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8759              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8760              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8761     PetscLogFlops(18.0 + 12.0);
8762   }
8763   if (invJ) {
8764     const PetscReal invDet = 1.0/(*detJ);
8765 
8766     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8767     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8768     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8769     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8770     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8771     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8772     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8773     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8774     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8775     PetscLogFlops(37.0);
8776   }
8777   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8778   PetscFunctionReturn(0);
8779 }
8780 
8781 #undef __FUNCT__
8782 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8783 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8784 {
8785   PetscSection       coordSection;
8786   Vec                coordinates;
8787   const PetscScalar *coords;
8788   const PetscInt     dim = 3;
8789   PetscInt           d;
8790   PetscErrorCode     ierr;
8791 
8792   PetscFunctionBegin;
8793   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8794   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8795   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8796   if (v0) {
8797     for (d = 0; d < dim; d++) {
8798       v0[d] = PetscRealPart(coords[d]);
8799     }
8800   }
8801   if (J) {
8802     for (d = 0; d < dim; d++) {
8803       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8804       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8805       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8806     }
8807     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8808              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8809              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8810     PetscLogFlops(18.0 + 12.0);
8811   }
8812   if (invJ) {
8813     const PetscReal invDet = -1.0/(*detJ);
8814 
8815     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8816     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8817     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8818     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8819     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8820     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8821     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8822     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8823     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8824     PetscLogFlops(37.0);
8825   }
8826   *detJ *= 8.0;
8827   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8828   PetscFunctionReturn(0);
8829 }
8830 
8831 #undef __FUNCT__
8832 #define __FUNCT__ "DMPlexComputeCellGeometry"
8833 /*@C
8834   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8835 
8836   Collective on DM
8837 
8838   Input Arguments:
8839 + dm   - the DM
8840 - cell - the cell
8841 
8842   Output Arguments:
8843 + v0   - the translation part of this affine transform
8844 . J    - the Jacobian of the transform to the reference element
8845 . invJ - the inverse of the Jacobian
8846 - detJ - the Jacobian determinant
8847 
8848   Level: advanced
8849 
8850 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8851 @*/
8852 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
8853 {
8854   PetscInt       dim, coneSize;
8855   PetscErrorCode ierr;
8856 
8857   PetscFunctionBegin;
8858   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8859   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8860   switch(dim) {
8861   case 2:
8862     switch(coneSize) {
8863     case 3:
8864       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8865       break;
8866     case 4:
8867       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8868       break;
8869     default:
8870       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8871     }
8872     break;
8873   case 3:
8874     switch(coneSize) {
8875     case 4:
8876       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8877       break;
8878     case 8:
8879       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8880       break;
8881     default:
8882       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8883     }
8884     break;
8885   default:
8886     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8887   }
8888   PetscFunctionReturn(0);
8889 }
8890 
8891 #undef __FUNCT__
8892 #define __FUNCT__ "DMPlexGetFaceOrientation"
8893 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
8894 {
8895   MPI_Comm       comm      = ((PetscObject) dm)->comm;
8896   PetscBool      posOrient = PETSC_FALSE;
8897   const PetscInt debug     = 0;
8898   PetscInt       cellDim, faceSize, f;
8899   PetscErrorCode ierr;
8900 
8901   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
8902   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
8903 
8904   if (cellDim == numCorners-1) {
8905     /* Simplices */
8906     faceSize  = numCorners-1;
8907     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
8908   } else if (cellDim == 1 && numCorners == 3) {
8909     /* Quadratic line */
8910     faceSize  = 1;
8911     posOrient = PETSC_TRUE;
8912   } else if (cellDim == 2 && numCorners == 4) {
8913     /* Quads */
8914     faceSize  = 2;
8915     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
8916       posOrient = PETSC_TRUE;
8917     } else if ((indices[0] == 3) && (indices[1] == 0)) {
8918       posOrient = PETSC_TRUE;
8919     } else {
8920       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
8921         posOrient = PETSC_FALSE;
8922       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
8923     }
8924   } else if (cellDim == 2 && numCorners == 6) {
8925     /* Quadratic triangle (I hate this) */
8926     /* Edges are determined by the first 2 vertices (corners of edges) */
8927     const PetscInt faceSizeTri = 3;
8928     PetscInt  sortedIndices[3], i, iFace;
8929     PetscBool found = PETSC_FALSE;
8930     PetscInt  faceVerticesTriSorted[9] = {
8931       0, 3,  4, /* bottom */
8932       1, 4,  5, /* right */
8933       2, 3,  5, /* left */
8934     };
8935     PetscInt  faceVerticesTri[9] = {
8936       0, 3,  4, /* bottom */
8937       1, 4,  5, /* right */
8938       2, 5,  3, /* left */
8939     };
8940 
8941     faceSize = faceSizeTri;
8942     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
8943     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
8944     for (iFace = 0; iFace < 3; ++iFace) {
8945       const PetscInt ii = iFace*faceSizeTri;
8946       PetscInt       fVertex, cVertex;
8947 
8948       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
8949           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
8950         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
8951           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
8952             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
8953               faceVertices[fVertex] = origVertices[cVertex];
8954               break;
8955             }
8956           }
8957         }
8958         found = PETSC_TRUE;
8959         break;
8960       }
8961     }
8962     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
8963     if (posOriented) {*posOriented = PETSC_TRUE;}
8964     PetscFunctionReturn(0);
8965   } else if (cellDim == 2 && numCorners == 9) {
8966     /* Quadratic quad (I hate this) */
8967     /* Edges are determined by the first 2 vertices (corners of edges) */
8968     const PetscInt faceSizeQuad = 3;
8969     PetscInt  sortedIndices[3], i, iFace;
8970     PetscBool found = PETSC_FALSE;
8971     PetscInt  faceVerticesQuadSorted[12] = {
8972       0, 1,  4, /* bottom */
8973       1, 2,  5, /* right */
8974       2, 3,  6, /* top */
8975       0, 3,  7, /* left */
8976     };
8977     PetscInt  faceVerticesQuad[12] = {
8978       0, 1,  4, /* bottom */
8979       1, 2,  5, /* right */
8980       2, 3,  6, /* top */
8981       3, 0,  7, /* left */
8982     };
8983 
8984     faceSize = faceSizeQuad;
8985     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
8986     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
8987     for (iFace = 0; iFace < 4; ++iFace) {
8988       const PetscInt ii = iFace*faceSizeQuad;
8989       PetscInt       fVertex, cVertex;
8990 
8991       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
8992           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
8993         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
8994           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
8995             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
8996               faceVertices[fVertex] = origVertices[cVertex];
8997               break;
8998             }
8999           }
9000         }
9001         found = PETSC_TRUE;
9002         break;
9003       }
9004     }
9005     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9006     if (posOriented) {*posOriented = PETSC_TRUE;}
9007     PetscFunctionReturn(0);
9008   } else if (cellDim == 3 && numCorners == 8) {
9009     /* Hexes
9010        A hex is two oriented quads with the normal of the first
9011        pointing up at the second.
9012 
9013           7---6
9014          /|  /|
9015         4---5 |
9016         | 3-|-2
9017         |/  |/
9018         0---1
9019 
9020         Faces are determined by the first 4 vertices (corners of faces) */
9021     const PetscInt faceSizeHex = 4;
9022     PetscInt  sortedIndices[4], i, iFace;
9023     PetscBool found = PETSC_FALSE;
9024     PetscInt faceVerticesHexSorted[24] = {
9025       0, 1, 2, 3,  /* bottom */
9026       4, 5, 6, 7,  /* top */
9027       0, 1, 4, 5,  /* front */
9028       1, 2, 5, 6,  /* right */
9029       2, 3, 6, 7,  /* back */
9030       0, 3, 4, 7,  /* left */
9031     };
9032     PetscInt faceVerticesHex[24] = {
9033       3, 2, 1, 0,  /* bottom */
9034       4, 5, 6, 7,  /* top */
9035       0, 1, 5, 4,  /* front */
9036       1, 2, 6, 5,  /* right */
9037       2, 3, 7, 6,  /* back */
9038       3, 0, 4, 7,  /* left */
9039     };
9040 
9041     faceSize = faceSizeHex;
9042     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9043     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9044     for (iFace = 0; iFace < 6; ++iFace) {
9045       const PetscInt ii = iFace*faceSizeHex;
9046       PetscInt       fVertex, cVertex;
9047 
9048       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9049           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9050           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9051           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9052         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9053           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9054             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9055               faceVertices[fVertex] = origVertices[cVertex];
9056               break;
9057             }
9058           }
9059         }
9060         found = PETSC_TRUE;
9061         break;
9062       }
9063     }
9064     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9065     if (posOriented) {*posOriented = PETSC_TRUE;}
9066     PetscFunctionReturn(0);
9067   } else if (cellDim == 3 && numCorners == 10) {
9068     /* Quadratic tet */
9069     /* Faces are determined by the first 3 vertices (corners of faces) */
9070     const PetscInt faceSizeTet = 6;
9071     PetscInt  sortedIndices[6], i, iFace;
9072     PetscBool found = PETSC_FALSE;
9073     PetscInt faceVerticesTetSorted[24] = {
9074       0, 1, 2,  6, 7, 8, /* bottom */
9075       0, 3, 4,  6, 7, 9,  /* front */
9076       1, 4, 5,  7, 8, 9,  /* right */
9077       2, 3, 5,  6, 8, 9,  /* left */
9078     };
9079     PetscInt faceVerticesTet[24] = {
9080       0, 1, 2,  6, 7, 8, /* bottom */
9081       0, 4, 3,  6, 7, 9,  /* front */
9082       1, 5, 4,  7, 8, 9,  /* right */
9083       2, 3, 5,  8, 6, 9,  /* left */
9084     };
9085 
9086     faceSize = faceSizeTet;
9087     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9088     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9089     for (iFace=0; iFace < 4; ++iFace) {
9090       const PetscInt ii = iFace*faceSizeTet;
9091       PetscInt       fVertex, cVertex;
9092 
9093       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9094           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9095           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9096           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9097         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9098           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9099             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9100               faceVertices[fVertex] = origVertices[cVertex];
9101               break;
9102             }
9103           }
9104         }
9105         found = PETSC_TRUE;
9106         break;
9107       }
9108     }
9109     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9110     if (posOriented) {*posOriented = PETSC_TRUE;}
9111     PetscFunctionReturn(0);
9112   } else if (cellDim == 3 && numCorners == 27) {
9113     /* Quadratic hexes (I hate this)
9114        A hex is two oriented quads with the normal of the first
9115        pointing up at the second.
9116 
9117          7---6
9118         /|  /|
9119        4---5 |
9120        | 3-|-2
9121        |/  |/
9122        0---1
9123 
9124        Faces are determined by the first 4 vertices (corners of faces) */
9125     const PetscInt faceSizeQuadHex = 9;
9126     PetscInt  sortedIndices[9], i, iFace;
9127     PetscBool found = PETSC_FALSE;
9128     PetscInt faceVerticesQuadHexSorted[54] = {
9129       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9130       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9131       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9132       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9133       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9134       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9135     };
9136     PetscInt faceVerticesQuadHex[54] = {
9137       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9138       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9139       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9140       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9141       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9142       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9143     };
9144 
9145     faceSize = faceSizeQuadHex;
9146     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9147     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9148     for (iFace = 0; iFace < 6; ++iFace) {
9149       const PetscInt ii = iFace*faceSizeQuadHex;
9150       PetscInt       fVertex, cVertex;
9151 
9152       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9153           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9154           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9155           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9156         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9157           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9158             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9159               faceVertices[fVertex] = origVertices[cVertex];
9160               break;
9161             }
9162           }
9163         }
9164         found = PETSC_TRUE;
9165         break;
9166       }
9167     }
9168     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9169     if (posOriented) {*posOriented = PETSC_TRUE;}
9170     PetscFunctionReturn(0);
9171   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9172   if (!posOrient) {
9173     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9174     for (f = 0; f < faceSize; ++f) {
9175       faceVertices[f] = origVertices[faceSize-1 - f];
9176     }
9177   } else {
9178     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9179     for (f = 0; f < faceSize; ++f) {
9180       faceVertices[f] = origVertices[f];
9181     }
9182   }
9183   if (posOriented) {*posOriented = posOrient;}
9184   PetscFunctionReturn(0);
9185 }
9186 
9187 #undef __FUNCT__
9188 #define __FUNCT__ "DMPlexGetOrientedFace"
9189 /*
9190     Given a cell and a face, as a set of vertices,
9191       return the oriented face, as a set of vertices, in faceVertices
9192     The orientation is such that the face normal points out of the cell
9193 */
9194 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9195 {
9196   const PetscInt *cone = PETSC_NULL;
9197   PetscInt        coneSize, v, f, v2;
9198   PetscInt        oppositeVertex = -1;
9199   PetscErrorCode  ierr;
9200 
9201   PetscFunctionBegin;
9202   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9203   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9204   for (v = 0, v2 = 0; v < coneSize; ++v) {
9205     PetscBool found  = PETSC_FALSE;
9206 
9207     for (f = 0; f < faceSize; ++f) {
9208       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
9209     }
9210     if (found) {
9211       indices[v2]      = v;
9212       origVertices[v2] = cone[v];
9213       ++v2;
9214     } else {
9215       oppositeVertex = v;
9216     }
9217   }
9218   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9219   PetscFunctionReturn(0);
9220 }
9221 
9222 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9223 {
9224   switch(i) {
9225   case 0:
9226     switch(j) {
9227     case 0: return 0;
9228     case 1:
9229       switch(k) {
9230       case 0: return 0;
9231       case 1: return 0;
9232       case 2: return 1;
9233       }
9234     case 2:
9235       switch(k) {
9236       case 0: return 0;
9237       case 1: return -1;
9238       case 2: return 0;
9239       }
9240     }
9241   case 1:
9242     switch(j) {
9243     case 0:
9244       switch(k) {
9245       case 0: return 0;
9246       case 1: return 0;
9247       case 2: return -1;
9248       }
9249     case 1: return 0;
9250     case 2:
9251       switch(k) {
9252       case 0: return 1;
9253       case 1: return 0;
9254       case 2: return 0;
9255       }
9256     }
9257   case 2:
9258     switch(j) {
9259     case 0:
9260       switch(k) {
9261       case 0: return 0;
9262       case 1: return 1;
9263       case 2: return 0;
9264       }
9265     case 1:
9266       switch(k) {
9267       case 0: return -1;
9268       case 1: return 0;
9269       case 2: return 0;
9270       }
9271     case 2: return 0;
9272     }
9273   }
9274   return 0;
9275 }
9276 
9277 #undef __FUNCT__
9278 #define __FUNCT__ "DMPlexCreateRigidBody"
9279 /*@C
9280   DMPlexCreateRigidBody - create rigid body modes from coordinates
9281 
9282   Collective on DM
9283 
9284   Input Arguments:
9285 + dm - the DM
9286 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9287 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9288 
9289   Output Argument:
9290 . sp - the null space
9291 
9292   Note: This is necessary to take account of Dirichlet conditions on the displacements
9293 
9294   Level: advanced
9295 
9296 .seealso: MatNullSpaceCreate()
9297 @*/
9298 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9299 {
9300   MPI_Comm       comm = ((PetscObject) dm)->comm;
9301   Vec            coordinates, localMode, mode[6];
9302   PetscSection   coordSection;
9303   PetscScalar   *coords;
9304   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9305   PetscErrorCode ierr;
9306 
9307   PetscFunctionBegin;
9308   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9309   if (dim == 1) {
9310     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9311     PetscFunctionReturn(0);
9312   }
9313   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9314   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9315   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9316   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9317   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9318   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9319   m    = (dim*(dim+1))/2;
9320   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9321   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9322   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9323   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9324   /* Assume P1 */
9325   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9326   for (d = 0; d < dim; ++d) {
9327     PetscScalar values[3] = {0.0, 0.0, 0.0};
9328 
9329     values[d] = 1.0;
9330     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9331     for (v = vStart; v < vEnd; ++v) {
9332       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9333     }
9334     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9335     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9336   }
9337   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9338   for (d = dim; d < dim*(dim+1)/2; ++d) {
9339     PetscInt i, j, k = dim > 2 ? d - dim : d;
9340 
9341     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9342     for (v = vStart; v < vEnd; ++v) {
9343       PetscScalar values[3] = {0.0, 0.0, 0.0};
9344       PetscInt    off;
9345 
9346       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9347       for (i = 0; i < dim; ++i) {
9348         for (j = 0; j < dim; ++j) {
9349           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9350         }
9351       }
9352       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9353     }
9354     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9355     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9356   }
9357   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9358   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9359   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9360   /* Orthonormalize system */
9361   for (i = dim; i < m; ++i) {
9362     PetscScalar dots[6];
9363 
9364     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9365     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9366     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9367     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9368   }
9369   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9370   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9371   PetscFunctionReturn(0);
9372 }
9373 
9374 #undef __FUNCT__
9375 #define __FUNCT__ "DMPlexGetHybridBounds"
9376 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9377 {
9378   DM_Plex       *mesh = (DM_Plex *) dm->data;
9379   PetscInt       dim;
9380   PetscErrorCode ierr;
9381 
9382   PetscFunctionBegin;
9383   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9384   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9385   if (cMax) *cMax = mesh->hybridPointMax[dim];
9386   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9387   if (eMax) *eMax = mesh->hybridPointMax[1];
9388   if (vMax) *vMax = mesh->hybridPointMax[0];
9389   PetscFunctionReturn(0);
9390 }
9391 
9392 #undef __FUNCT__
9393 #define __FUNCT__ "DMPlexSetHybridBounds"
9394 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9395 {
9396   DM_Plex       *mesh = (DM_Plex *) dm->data;
9397   PetscInt       dim;
9398   PetscErrorCode ierr;
9399 
9400   PetscFunctionBegin;
9401   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9402   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9403   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9404   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9405   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9406   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9407   PetscFunctionReturn(0);
9408 }
9409 
9410 #undef __FUNCT__
9411 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9412 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9413 {
9414   DM_Plex *mesh = (DM_Plex *) dm->data;
9415 
9416   PetscFunctionBegin;
9417   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9418   PetscValidPointer(cellHeight, 2);
9419   *cellHeight = mesh->vtkCellHeight;
9420   PetscFunctionReturn(0);
9421 }
9422 
9423 #undef __FUNCT__
9424 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9425 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9426 {
9427   DM_Plex *mesh = (DM_Plex *) dm->data;
9428 
9429   PetscFunctionBegin;
9430   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9431   mesh->vtkCellHeight = cellHeight;
9432   PetscFunctionReturn(0);
9433 }
9434 
9435 #undef __FUNCT__
9436 #define __FUNCT__ "DMPlexInsertFace_Private"
9437 /*
9438   DMPlexInsertFace_Private - Puts a face into the mesh
9439 
9440   Not collective
9441 
9442   Input Parameters:
9443   + dm              - The DMPlex
9444   . numFaceVertex   - The number of vertices in the face
9445   . faceVertices    - The vertices in the face for dm
9446   . subfaceVertices - The vertices in the face for subdm
9447   . numCorners      - The number of vertices in the cell
9448   . cell            - A cell in dm containing the face
9449   . subcell         - A cell in subdm containing the face
9450   . firstFace       - First face in the mesh
9451   - newFacePoint    - Next face in the mesh
9452 
9453   Output Parameters:
9454   . newFacePoint - Contains next face point number on input, updated on output
9455 
9456   Level: developer
9457 */
9458 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)
9459 {
9460   MPI_Comm        comm    = ((PetscObject) dm)->comm;
9461   DM_Plex     *submesh = (DM_Plex *) subdm->data;
9462   const PetscInt *faces;
9463   PetscInt        numFaces, coneSize;
9464   PetscErrorCode  ierr;
9465 
9466   PetscFunctionBegin;
9467   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9468   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9469 #if 0
9470   /* Cannot use this because support() has not been constructed yet */
9471   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9472 #else
9473   {
9474     PetscInt f;
9475 
9476     numFaces = 0;
9477     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
9478     for(f = firstFace; f < *newFacePoint; ++f) {
9479       PetscInt dof, off, d;
9480 
9481       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9482       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9483       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9484       for(d = 0; d < dof; ++d) {
9485         const PetscInt p = submesh->cones[off+d];
9486         PetscInt       v;
9487 
9488         for(v = 0; v < numFaceVertices; ++v) {
9489           if (subfaceVertices[v] == p) break;
9490         }
9491         if (v == numFaceVertices) break;
9492       }
9493       if (d == dof) {
9494         numFaces = 1;
9495         ((PetscInt *) faces)[0] = f;
9496       }
9497     }
9498   }
9499 #endif
9500   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
9501   else if (numFaces == 1) {
9502     /* Add the other cell neighbor for this face */
9503     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
9504   } else {
9505     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
9506     PetscBool posOriented;
9507 
9508     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9509     origVertices = &orientedVertices[numFaceVertices];
9510     indices      = &orientedVertices[numFaceVertices*2];
9511     orientedSubVertices = &orientedVertices[numFaceVertices*3];
9512     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
9513     /* TODO: I know that routine should return a permutation, not the indices */
9514     for(v = 0; v < numFaceVertices; ++v) {
9515       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
9516       for(ov = 0; ov < numFaceVertices; ++ov) {
9517         if (orientedVertices[ov] == vertex) {
9518           orientedSubVertices[ov] = subvertex;
9519           break;
9520         }
9521       }
9522       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
9523     }
9524     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
9525     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
9526     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9527     ++(*newFacePoint);
9528   }
9529   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9530   PetscFunctionReturn(0);
9531 }
9532 
9533 #undef __FUNCT__
9534 #define __FUNCT__ "DMPlexCreateSubmesh"
9535 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
9536 {
9537   MPI_Comm        comm = ((PetscObject) dm)->comm;
9538   DM_Plex     *submesh;
9539   PetscBool       boundaryFaces = PETSC_FALSE;
9540   PetscSection    coordSection, subCoordSection;
9541   Vec             coordinates, subCoordinates;
9542   PetscScalar    *coords, *subCoords;
9543   IS              labelIS;
9544   const PetscInt *subVertices;
9545   PetscInt       *subVerticesActive, *tmpPoints;
9546   PetscInt       *subCells = PETSC_NULL;
9547   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
9548   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
9549   PetscInt        dim; /* Right now, do not specify dimension */
9550   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
9551   PetscErrorCode  ierr;
9552 
9553   PetscFunctionBegin;
9554   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9555   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9556   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9557   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
9558   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
9559   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9560   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9561   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9562   subface = &face[maxConeSize];
9563   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
9564   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
9565   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
9566   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
9567   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
9568   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
9569   maxSubCells = numSubVertices;
9570   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
9571   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
9572   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
9573   for(v = 0; v < numSubVertices; ++v) {
9574     const PetscInt vertex = subVertices[v];
9575     PetscInt *star = PETSC_NULL;
9576     PetscInt  starSize, numCells = 0;
9577 
9578     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9579     for(p = 0; p < starSize*2; p += 2) {
9580       const PetscInt point = star[p];
9581       if ((point >= cStart) && (point < cEnd)) {
9582         star[numCells++] = point;
9583       }
9584     }
9585     numOldSubCells = numSubCells;
9586     for(c = 0; c < numCells; ++c) {
9587       const PetscInt cell    = star[c];
9588       PetscInt      *closure = PETSC_NULL;
9589       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9590       PetscInt       cellLoc;
9591 
9592       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9593       if (cellLoc >= 0) continue;
9594       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9595       for(p = 0; p < closureSize*2; p += 2) {
9596         const PetscInt point = closure[p];
9597         if ((point >= vStart) && (point < vEnd)) {
9598           closure[numCorners++] = point;
9599         }
9600       }
9601       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9602       for(corner = 0; corner < numCorners; ++corner) {
9603         const PetscInt cellVertex = closure[corner];
9604         PetscInt       subVertex;
9605 
9606         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
9607         if (subVertex >= 0) { /* contains submesh vertex */
9608           for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9609           if (i == faceSize) {
9610             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
9611             face[faceSize]    = cellVertex;
9612             subface[faceSize] = subVertex;
9613             ++faceSize;
9614           }
9615         }
9616       }
9617       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9618       if (faceSize >= nFV) {
9619         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9620         if (numSubCells >= maxSubCells) {
9621           PetscInt *tmpCells;
9622           maxSubCells *= 2;
9623           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
9624           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
9625           ierr = PetscFree(subCells);CHKERRQ(ierr);
9626           subCells = tmpCells;
9627         }
9628         /* TOOD: Maybe overestimate then squeeze out empty faces */
9629         if (faceSize > nFV) {
9630           /* TODO: This is tricky. Maybe just add all faces */
9631           numSubFaces++;
9632         } else {
9633           numSubFaces++;
9634         }
9635         for(f = 0; f < faceSize; ++f) {
9636           subVerticesActive[subface[f]] = 1;
9637         }
9638         subCells[numSubCells++] = cell;
9639       }
9640     }
9641     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9642     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
9643   }
9644   /* Pick out active subvertices */
9645   for(v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
9646     if (subVerticesActive[v]) {
9647       subVerticesActive[numSubVerticesActive++] = subVertices[v];
9648     }
9649   }
9650   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
9651   /* Set cone sizes */
9652   firstSubVertex = numSubCells;
9653   firstSubFace   = numSubCells+numSubVerticesActive;
9654   newFacePoint   = firstSubFace;
9655   for(c = 0; c < numSubCells; ++c) {
9656     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
9657   }
9658   for(f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
9659     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
9660   }
9661   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
9662   /* Create face cones */
9663   for(c = 0; c < numSubCells; ++c) {
9664     const PetscInt cell    = subCells[c];
9665     PetscInt      *closure = PETSC_NULL;
9666     PetscInt       closureSize, numCorners = 0, faceSize = 0;
9667 
9668     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9669     for(p = 0; p < closureSize*2; p += 2) {
9670       const PetscInt point = closure[p];
9671       if ((point >= vStart) && (point < vEnd)) {
9672         closure[numCorners++] = point;
9673       }
9674     }
9675     for(corner = 0; corner < numCorners; ++corner) {
9676       const PetscInt cellVertex = closure[corner];
9677       PetscInt       subVertex;
9678 
9679       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
9680       if (subVertex >= 0) { /* contains submesh vertex */
9681         for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9682         if (i == faceSize) {
9683           face[faceSize]    = cellVertex;
9684           subface[faceSize] = numSubCells+subVertex;
9685           ++faceSize;
9686         }
9687       }
9688     }
9689     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9690     if (faceSize >= nFV) {
9691       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9692       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
9693       /*   We have to take all the faces, and discard those in the interior */
9694       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
9695 #if 0
9696       /* This object just calls insert on each face that comes from subsets() */
9697       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
9698       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
9699       PointArray                          faceVec(face->begin(), face->end());
9700 
9701       subsets(faceVec, nFV, inserter);
9702 #endif
9703       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
9704     }
9705   }
9706   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
9707   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
9708   /* Build coordinates */
9709   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9710   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9711   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
9712   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
9713   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
9714     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
9715   }
9716   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
9717   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
9718   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
9719   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
9720   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
9721   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
9722   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9723   for(v = 0; v < numSubVerticesActive; ++v) {
9724     const PetscInt vertex    = subVerticesActive[v];
9725     const PetscInt subVertex = firstSubVertex+v;
9726     PetscInt dof, off, sdof, soff;
9727 
9728     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
9729     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
9730     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
9731     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
9732     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
9733     for(d = 0; d < dof; ++d) {
9734       subCoords[soff+d] = coords[off+d];
9735     }
9736   }
9737   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
9738   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9739   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
9740   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
9741 
9742   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
9743   /* Create map from submesh points to original mesh points */
9744   submesh = (DM_Plex *) (*subdm)->data;
9745   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
9746   for(c = 0; c < numSubCells; ++c) {
9747     tmpPoints[c] = subCells[c];
9748   }
9749   for(v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
9750     tmpPoints[v] = subVerticesActive[v-numSubCells];
9751   }
9752   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
9753 
9754   ierr = PetscFree(subCells);CHKERRQ(ierr);
9755   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
9756   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
9757   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
9758   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9759   PetscFunctionReturn(0);
9760 }
9761 
9762 #undef __FUNCT__
9763 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9764 /* We can easily have a form that takes an IS instead */
9765 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9766 {
9767   PetscSection   section, globalSection;
9768   PetscInt      *numbers, p;
9769   PetscErrorCode ierr;
9770 
9771   PetscFunctionBegin;
9772   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
9773   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9774   for(p = pStart; p < pEnd; ++p) {
9775     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9776   }
9777   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9778   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9779   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9780   for(p = pStart; p < pEnd; ++p) {
9781     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9782   }
9783   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9784   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9785   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9786   PetscFunctionReturn(0);
9787 }
9788 
9789 #undef __FUNCT__
9790 #define __FUNCT__ "DMPlexGetCellNumbering"
9791 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9792 {
9793   DM_Plex    *mesh = (DM_Plex *) dm->data;
9794   PetscInt       cellHeight, cStart, cEnd, cMax;
9795   PetscErrorCode ierr;
9796 
9797   PetscFunctionBegin;
9798   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9799   if (!mesh->globalCellNumbers) {
9800     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9801     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9802     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
9803     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9804     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9805   }
9806   *globalCellNumbers = mesh->globalCellNumbers;
9807   PetscFunctionReturn(0);
9808 }
9809 
9810 #undef __FUNCT__
9811 #define __FUNCT__ "DMPlexGetVertexNumbering"
9812 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9813 {
9814   DM_Plex    *mesh = (DM_Plex *) dm->data;
9815   PetscInt       vStart, vEnd, vMax;
9816   PetscErrorCode ierr;
9817 
9818   PetscFunctionBegin;
9819   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9820   if (!mesh->globalVertexNumbers) {
9821     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9822     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
9823     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9824     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9825   }
9826   *globalVertexNumbers = mesh->globalVertexNumbers;
9827   PetscFunctionReturn(0);
9828 }
9829 
9830 #undef __FUNCT__
9831 #define __FUNCT__ "DMPlexGetSubpointMap"
9832 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
9833 {
9834   DM_Plex *mesh = (DM_Plex *) dm->data;
9835 
9836   PetscFunctionBegin;
9837   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9838   PetscValidPointer(subpointMap, 2);
9839   *subpointMap = mesh->subpointMap;
9840   PetscFunctionReturn(0);
9841 }
9842 
9843 #undef __FUNCT__
9844 #define __FUNCT__ "DMPlexSetSubpointMap"
9845 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
9846 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
9847 {
9848   DM_Plex *mesh = (DM_Plex *) dm->data;
9849 
9850   PetscFunctionBegin;
9851   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9852   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
9853   mesh->subpointMap = subpointMap;
9854   PetscFunctionReturn(0);
9855 }
9856 
9857 #undef __FUNCT__
9858 #define __FUNCT__ "DMPlexGetScale"
9859 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9860 {
9861   DM_Plex *mesh = (DM_Plex *) dm->data;
9862 
9863   PetscFunctionBegin;
9864   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9865   PetscValidPointer(scale, 3);
9866   *scale = mesh->scale[unit];
9867   PetscFunctionReturn(0);
9868 }
9869 
9870 #undef __FUNCT__
9871 #define __FUNCT__ "DMPlexSetScale"
9872 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9873 {
9874   DM_Plex *mesh = (DM_Plex *) dm->data;
9875 
9876   PetscFunctionBegin;
9877   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9878   mesh->scale[unit] = scale;
9879   PetscFunctionReturn(0);
9880 }
9881 
9882 
9883 /*******************************************************************************
9884 This should be in a separate Discretization object, but I am not sure how to lay
9885 it out yet, so I am stuffing things here while I experiment.
9886 *******************************************************************************/
9887 #undef __FUNCT__
9888 #define __FUNCT__ "DMPlexSetFEMIntegration"
9889 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9890                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9891                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9892                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9893                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9894                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9895                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9896                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9897                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9898                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9899                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9900                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9901                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9902                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9903                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9904                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9905                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9906 {
9907   DM_Plex *mesh = (DM_Plex *) dm->data;
9908 
9909   PetscFunctionBegin;
9910   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9911   mesh->integrateResidualFEM       = integrateResidualFEM;
9912   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9913   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9914   PetscFunctionReturn(0);
9915 }
9916 
9917 #undef __FUNCT__
9918 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9919 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9920 {
9921   Vec            coordinates;
9922   PetscSection   section, cSection;
9923   PetscInt       dim, vStart, vEnd, v, c, d;
9924   PetscScalar   *values, *cArray;
9925   PetscReal     *coords;
9926   PetscErrorCode ierr;
9927 
9928   PetscFunctionBegin;
9929   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9930   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9931   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9932   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9933   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9934   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9935   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9936   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9937   for (v = vStart; v < vEnd; ++v) {
9938     PetscInt dof, off;
9939 
9940     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9941     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9942     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9943     for(d = 0; d < dof; ++d) {
9944       coords[d] = PetscRealPart(cArray[off+d]);
9945     }
9946     for(c = 0; c < numComp; ++c) {
9947       values[c] = (*funcs[c])(coords);
9948     }
9949     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9950   }
9951   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9952   /* Temporary, must be replaced by a projection on the finite element basis */
9953   {
9954     PetscInt eStart = 0, eEnd = 0, e, depth;
9955 
9956     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9957     --depth;
9958     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9959     for (e = eStart; e < eEnd; ++e) {
9960       const PetscInt *cone = PETSC_NULL;
9961       PetscInt        coneSize, d;
9962       PetscScalar    *coordsA, *coordsB;
9963 
9964       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9965       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9966       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9967       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9968       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9969       for (d = 0; d < dim; ++d) {
9970         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9971       }
9972       for (c = 0; c < numComp; ++c) {
9973         values[c] = (*funcs[c])(coords);
9974       }
9975       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9976     }
9977   }
9978 
9979   ierr = PetscFree(coords);CHKERRQ(ierr);
9980   ierr = PetscFree(values);CHKERRQ(ierr);
9981 #if 0
9982   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9983   PetscReal      detJ;
9984 
9985   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9986   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9987   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9988 
9989   for (PetscInt c = cStart; c < cEnd; ++c) {
9990     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9991     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9992     const int                          oSize   = pV.getSize();
9993     int                                v       = 0;
9994 
9995     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
9996     for (PetscInt cl = 0; cl < oSize; ++cl) {
9997       const PetscInt fDim;
9998 
9999       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10000       if (pointDim) {
10001         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10002           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10003         }
10004       }
10005     }
10006     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10007     pV.clear();
10008   }
10009   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10010   ierr = PetscFree(values);CHKERRQ(ierr);
10011 #endif
10012   PetscFunctionReturn(0);
10013 }
10014 
10015 #undef __FUNCT__
10016 #define __FUNCT__ "DMPlexProjectFunction"
10017 /*@C
10018   DMPlexProjectFunction - This projects the given function into the function space provided.
10019 
10020   Input Parameters:
10021 + dm      - The DM
10022 . numComp - The number of components (functions)
10023 . funcs   - The coordinate functions to evaluate
10024 - mode    - The insertion mode for values
10025 
10026   Output Parameter:
10027 . X - vector
10028 
10029   Level: developer
10030 
10031   Note:
10032   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10033   We will eventually fix it.
10034 
10035 ,seealso: DMPlexComputeL2Diff()
10036 */
10037 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10038 {
10039   Vec            localX;
10040   PetscErrorCode ierr;
10041 
10042   PetscFunctionBegin;
10043   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10044   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10045   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10046   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10047   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10048   PetscFunctionReturn(0);
10049 }
10050 
10051 #undef __FUNCT__
10052 #define __FUNCT__ "DMPlexComputeL2Diff"
10053 /*@C
10054   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10055 
10056   Input Parameters:
10057 + dm    - The DM
10058 . quad  - The PetscQuadrature object for each field
10059 . funcs - The functions to evaluate for each field component
10060 - X     - The coefficient vector u_h
10061 
10062   Output Parameter:
10063 . diff - The diff ||u - u_h||_2
10064 
10065   Level: developer
10066 
10067 .seealso: DMPlexProjectFunction()
10068 */
10069 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10070 {
10071   const PetscInt   debug = 0;
10072   PetscSection     section;
10073   Vec              localX;
10074   PetscReal       *coords, *v0, *J, *invJ, detJ;
10075   PetscReal        localDiff = 0.0;
10076   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10077   PetscErrorCode   ierr;
10078 
10079   PetscFunctionBegin;
10080   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10081   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10082   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10083   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10084   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10085   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10086   for (field = 0; field < numFields; ++field) {
10087     numComponents += quad[field].numComponents;
10088   }
10089   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10090   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10091   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10092   for (c = cStart; c < cEnd; ++c) {
10093     const PetscScalar *x;
10094     PetscReal          elemDiff = 0.0;
10095 
10096     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10097     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10098     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10099 
10100     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10101       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10102       const PetscReal *quadPoints    = quad[field].quadPoints;
10103       const PetscReal *quadWeights   = quad[field].quadWeights;
10104       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10105       const PetscInt   numBasisComps = quad[field].numComponents;
10106       const PetscReal *basis         = quad[field].basis;
10107       PetscInt         q, d, e, fc, f;
10108 
10109       if (debug) {
10110         char title[1024];
10111         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10112         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10113       }
10114       for (q = 0; q < numQuadPoints; ++q) {
10115         for (d = 0; d < dim; d++) {
10116           coords[d] = v0[d];
10117           for (e = 0; e < dim; e++) {
10118             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10119           }
10120         }
10121         for (fc = 0; fc < numBasisComps; ++fc) {
10122           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10123           PetscReal       interpolant = 0.0;
10124           for (f = 0; f < numBasisFuncs; ++f) {
10125             const PetscInt fidx = f*numBasisComps+fc;
10126             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10127           }
10128           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10129           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10130         }
10131       }
10132       comp        += numBasisComps;
10133       fieldOffset += numBasisFuncs*numBasisComps;
10134     }
10135     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10136     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10137     localDiff += elemDiff;
10138   }
10139   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10140   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10141   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10142   *diff = PetscSqrtReal(*diff);
10143   PetscFunctionReturn(0);
10144 }
10145 
10146 #undef __FUNCT__
10147 #define __FUNCT__ "DMPlexComputeResidualFEM"
10148 /*@
10149   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10150 
10151   Input Parameters:
10152 + dm - The mesh
10153 . X  - Local input vector
10154 - user - The user context
10155 
10156   Output Parameter:
10157 . F  - Local output vector
10158 
10159   Note:
10160   The second member of the user context must be an FEMContext.
10161 
10162   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10163   like a GPU, or vectorize on a multicore machine.
10164 
10165 .seealso: DMPlexComputeJacobianActionFEM()
10166 */
10167 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10168 {
10169   DM_Plex      *mesh = (DM_Plex *) dm->data;
10170   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10171   PetscQuadrature *quad = fem->quad;
10172   PetscSection     section;
10173   PetscReal       *v0, *J, *invJ, *detJ;
10174   PetscScalar     *elemVec, *u;
10175   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10176   PetscInt         cellDof = 0, numComponents = 0;
10177   PetscErrorCode   ierr;
10178 
10179   PetscFunctionBegin;
10180   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10181   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10182   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10183   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10184   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10185   numCells = cEnd - cStart;
10186   for (field = 0; field < numFields; ++field) {
10187     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10188     numComponents += quad[field].numComponents;
10189   }
10190   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10191   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10192   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);
10193   for (c = cStart; c < cEnd; ++c) {
10194     const PetscScalar *x;
10195     PetscInt           i;
10196 
10197     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10198     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10199     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10200 
10201     for (i = 0; i < cellDof; ++i) {
10202       u[c*cellDof+i] = x[i];
10203     }
10204     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10205   }
10206   for (field = 0; field < numFields; ++field) {
10207     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10208     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10209     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10210     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10211     /* Conforming batches */
10212     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10213     PetscInt numBlocks  = 1;
10214     PetscInt batchSize  = numBlocks * blockSize;
10215     PetscInt numBatches = numBatchesTmp;
10216     PetscInt numChunks  = numCells / (numBatches*batchSize);
10217     /* Remainder */
10218     PetscInt numRemainder = numCells % (numBatches * batchSize);
10219     PetscInt offset       = numCells - numRemainder;
10220 
10221     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10222     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10223                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10224   }
10225   for (c = cStart; c < cEnd; ++c) {
10226     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10227     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10228   }
10229   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10230   if (mesh->printFEM) {
10231     PetscMPIInt rank, numProcs;
10232     PetscInt    p;
10233 
10234     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10235     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10236     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10237     for (p = 0; p < numProcs; ++p) {
10238       if (p == rank) {
10239         Vec f;
10240 
10241         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10242         ierr = VecCopy(F, f);CHKERRQ(ierr);
10243         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10244         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10245         ierr = VecDestroy(&f);CHKERRQ(ierr);
10246         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10247       }
10248       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10249     }
10250   }
10251   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10252   PetscFunctionReturn(0);
10253 }
10254 
10255 #undef __FUNCT__
10256 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10257 /*@C
10258   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10259 
10260   Input Parameters:
10261 + dm - The mesh
10262 . J  - The Jacobian shell matrix
10263 . X  - Local input vector
10264 - user - The user context
10265 
10266   Output Parameter:
10267 . F  - Local output vector
10268 
10269   Note:
10270   The second member of the user context must be an FEMContext.
10271 
10272   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10273   like a GPU, or vectorize on a multicore machine.
10274 
10275 .seealso: DMPlexComputeResidualFEM()
10276 */
10277 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10278 {
10279   DM_Plex      *mesh = (DM_Plex *) dm->data;
10280   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10281   PetscQuadrature *quad = fem->quad;
10282   PetscSection     section;
10283   JacActionCtx    *jctx;
10284   PetscReal       *v0, *J, *invJ, *detJ;
10285   PetscScalar     *elemVec, *u, *a;
10286   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10287   PetscInt         cellDof = 0;
10288   PetscErrorCode   ierr;
10289 
10290   PetscFunctionBegin;
10291   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10292   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10293   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10294   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10295   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10296   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10297   numCells = cEnd - cStart;
10298   for (field = 0; field < numFields; ++field) {
10299     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10300   }
10301   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10302   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);
10303   for (c = cStart; c < cEnd; ++c) {
10304     const PetscScalar *x;
10305     PetscInt           i;
10306 
10307     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10308     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10309     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10310     for (i = 0; i < cellDof; ++i) {
10311       u[c*cellDof+i] = x[i];
10312     }
10313     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10314     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10315     for (i = 0; i < cellDof; ++i) {
10316       a[c*cellDof+i] = x[i];
10317     }
10318     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10319   }
10320   for (field = 0; field < numFields; ++field) {
10321     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10322     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10323     /* Conforming batches */
10324     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10325     PetscInt numBlocks  = 1;
10326     PetscInt batchSize  = numBlocks * blockSize;
10327     PetscInt numBatches = numBatchesTmp;
10328     PetscInt numChunks  = numCells / (numBatches*batchSize);
10329     /* Remainder */
10330     PetscInt numRemainder = numCells % (numBatches * batchSize);
10331     PetscInt offset       = numCells - numRemainder;
10332 
10333     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);
10334     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],
10335                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10336   }
10337   for (c = cStart; c < cEnd; ++c) {
10338     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10339     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10340   }
10341   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10342   if (mesh->printFEM) {
10343     PetscMPIInt rank, numProcs;
10344     PetscInt    p;
10345 
10346     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10347     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10348     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10349     for (p = 0; p < numProcs; ++p) {
10350       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10351       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10352     }
10353   }
10354   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10355   PetscFunctionReturn(0);
10356 }
10357 
10358 #undef __FUNCT__
10359 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10360 /*@
10361   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10362 
10363   Input Parameters:
10364 + dm - The mesh
10365 . X  - Local input vector
10366 - user - The user context
10367 
10368   Output Parameter:
10369 . Jac  - Jacobian matrix
10370 
10371   Note:
10372   The second member of the user context must be an FEMContext.
10373 
10374   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10375   like a GPU, or vectorize on a multicore machine.
10376 
10377 .seealso: FormFunctionLocal()
10378 */
10379 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10380 {
10381   DM_Plex      *mesh = (DM_Plex *) dm->data;
10382   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10383   PetscQuadrature *quad = fem->quad;
10384   PetscSection     section;
10385   PetscReal       *v0, *J, *invJ, *detJ;
10386   PetscScalar     *elemMat, *u;
10387   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10388   PetscInt         cellDof = 0, numComponents = 0;
10389   PetscBool        isShell;
10390   PetscErrorCode   ierr;
10391 
10392   PetscFunctionBegin;
10393   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10394   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10395   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10396   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10397   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10398   numCells = cEnd - cStart;
10399   for (field = 0; field < numFields; ++field) {
10400     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10401     numComponents += quad[field].numComponents;
10402   }
10403   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10404   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10405   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);
10406   for (c = cStart; c < cEnd; ++c) {
10407     const PetscScalar *x;
10408     PetscInt           i;
10409 
10410     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10411     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10412     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10413 
10414     for (i = 0; i < cellDof; ++i) {
10415       u[c*cellDof+i] = x[i];
10416     }
10417     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10418   }
10419   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10420   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10421     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10422     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10423     PetscInt       fieldJ;
10424 
10425     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10426       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10427       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10428       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10429       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10430       /* Conforming batches */
10431       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10432       PetscInt numBlocks  = 1;
10433       PetscInt batchSize  = numBlocks * blockSize;
10434       PetscInt numBatches = numBatchesTmp;
10435       PetscInt numChunks  = numCells / (numBatches*batchSize);
10436       /* Remainder */
10437       PetscInt numRemainder = numCells % (numBatches * batchSize);
10438       PetscInt offset       = numCells - numRemainder;
10439 
10440       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10441       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10442                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10443     }
10444   }
10445   for (c = cStart; c < cEnd; ++c) {
10446     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10447     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10448   }
10449   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10450 
10451   /* Assemble matrix, using the 2-step process:
10452        MatAssemblyBegin(), MatAssemblyEnd(). */
10453   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10454   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10455 
10456   if (mesh->printFEM) {
10457     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10458     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10459     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10460   }
10461   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10462   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10463   if (isShell) {
10464     JacActionCtx *jctx;
10465 
10466     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10467     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10468   }
10469   *str = SAME_NONZERO_PATTERN;
10470   PetscFunctionReturn(0);
10471 }
10472 
10473 
10474 #undef __FUNCT__
10475 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10476 /*@C
10477   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10478   the local section and an SF describing the section point overlap.
10479 
10480   Input Parameters:
10481   + s - The PetscSection for the local field layout
10482   . sf - The SF describing parallel layout of the section points
10483   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10484   . label - The label specifying the points
10485   - labelValue - The label stratum specifying the points
10486 
10487   Output Parameter:
10488   . gsection - The PetscSection for the global field layout
10489 
10490   Note: This gives negative sizes and offsets to points not owned by this process
10491 
10492   Level: developer
10493 
10494 .seealso: PetscSectionCreate()
10495 @*/
10496 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10497 {
10498   PetscInt      *neg;
10499   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10500   PetscErrorCode ierr;
10501 
10502   PetscFunctionBegin;
10503   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10504   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10505   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10506   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10507   /* Mark ghost points with negative dof */
10508   for (p = pStart; p < pEnd; ++p) {
10509     PetscInt value;
10510 
10511     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
10512     if (value != labelValue) continue;
10513     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
10514     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
10515     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
10516     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
10517     neg[p-pStart] = -(dof+1);
10518   }
10519   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
10520   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10521   if (nroots >= 0) {
10522     if (nroots > pEnd - pStart) {
10523       PetscInt *tmpDof;
10524       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10525       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
10526       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10527       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10528       for (p = pStart; p < pEnd; ++p) {
10529         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
10530       }
10531       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
10532     } else {
10533       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10534       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10535     }
10536   }
10537   /* Calculate new sizes, get proccess offset, and calculate point offsets */
10538   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10539     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
10540     (*gsection)->atlasOff[p] = off;
10541     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
10542   }
10543   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
10544   globalOff -= off;
10545   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10546     (*gsection)->atlasOff[p] += globalOff;
10547     neg[p] = -((*gsection)->atlasOff[p]+1);
10548   }
10549   /* Put in negative offsets for ghost points */
10550   if (nroots >= 0) {
10551     if (nroots > pEnd - pStart) {
10552       PetscInt *tmpOff;
10553       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10554       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
10555       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10556       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10557       for (p = pStart; p < pEnd; ++p) {
10558         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
10559       }
10560       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
10561     } else {
10562       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10563       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10564     }
10565   }
10566   ierr = PetscFree(neg);CHKERRQ(ierr);
10567   PetscFunctionReturn(0);
10568 }
10569