xref: /petsc/src/dm/impls/plex/plex.c (revision 39d7646b82f3c61fed60464cb8cf8b037dcb3c88)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/vecimpl.h>
4 #include <petsc-private/isimpl.h>
5 
6 /* Logging support */
7 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
8 
9 PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
11 
12 #undef __FUNCT__
13 #define __FUNCT__ "VecView_Plex_Local"
14 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
15 {
16   DM             dm;
17   PetscBool      isvtk;
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
22   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
23   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
24   if (isvtk) {
25     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
26     PetscSection            section;
27     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
28 
29     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
30     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
31     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
32     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, NULL);CHKERRQ(ierr);
33     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, NULL);CHKERRQ(ierr);
34     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
35     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
36     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
37     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
38     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
39     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
40       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
41     } else if (cdof && vdof) {
42       SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
43     } else if (cdof) {
44       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
45        * vector or just happens to have the same number of dofs as the dimension. */
46       if (cdof == dim) {
47         ft = PETSC_VTK_CELL_VECTOR_FIELD;
48       } else {
49         ft = PETSC_VTK_CELL_FIELD;
50       }
51     } else if (vdof) {
52       if (vdof == dim) {
53         ft = PETSC_VTK_POINT_VECTOR_FIELD;
54       } else {
55         ft = PETSC_VTK_POINT_FIELD;
56       }
57     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
58 
59     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
60     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
61     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
62   } else {
63     PetscBool isseq;
64 
65     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
66     if (isseq) {
67       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
68     } else {
69       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
70     }
71   }
72   PetscFunctionReturn(0);
73 }
74 
75 #undef __FUNCT__
76 #define __FUNCT__ "VecView_Plex"
77 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
78 {
79   DM             dm;
80   PetscBool      isvtk;
81   PetscErrorCode ierr;
82 
83   PetscFunctionBegin;
84   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
85   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
86   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
87   if (isvtk) {
88     Vec         locv;
89     const char *name;
90 
91     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
92     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
93     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
94     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
95     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
96     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
97     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
98   } else {
99     PetscBool isseq;
100 
101     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
102     if (isseq) {
103       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
104     } else {
105       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
106     }
107   }
108   PetscFunctionReturn(0);
109 }
110 
111 #undef __FUNCT__
112 #define __FUNCT__ "DMPlexView_Ascii"
113 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
114 {
115   DM_Plex          *mesh = (DM_Plex*) dm->data;
116   DM                cdm;
117   DMLabel           markers;
118   PetscSection      coordSection;
119   Vec               coordinates;
120   PetscViewerFormat format;
121   PetscErrorCode    ierr;
122 
123   PetscFunctionBegin;
124   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
125   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
126   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
127   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
128   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
129     const char *name;
130     PetscInt    maxConeSize, maxSupportSize;
131     PetscInt    pStart, pEnd, p;
132     PetscMPIInt rank, size;
133 
134     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
135     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
136     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
137     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
138     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
142     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
143     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
144     for (p = pStart; p < pEnd; ++p) {
145       PetscInt dof, off, s;
146 
147       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
148       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
149       for (s = off; s < off+dof; ++s) {
150         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
151       }
152     }
153     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
154     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
155     for (p = pStart; p < pEnd; ++p) {
156       PetscInt dof, off, c;
157 
158       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
159       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
160       for (c = off; c < off+dof; ++c) {
161         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
162       }
163     }
164     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
165     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
166     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
167     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
168     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors  = 3;
180     PetscReal    scale      = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for (p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for (v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for (e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for (c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscInt    numLabels, l;
282     PetscMPIInt size;
283 
284     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
285     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
286     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
287     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
288     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
289     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
290     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
291     if (depth == 1) {
292       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
293       pEnd = pEnd - pStart;
294       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
295       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
296       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
297       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
298       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
299       pEnd = pEnd - pStart;
300       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
301       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
302       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
303       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
304     } else {
305       for (d = 0; d <= dim; d++) {
306         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
307         pEnd = pEnd - pStart;
308         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
309         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
310         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
311         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
312       }
313     }
314     ierr = PetscFree(sizes);CHKERRQ(ierr);
315     ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
316     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
317     for (l = 0; l < numLabels; ++l) {
318       DMLabel         label;
319       const char     *name;
320       IS              valueIS;
321       const PetscInt *values;
322       PetscInt        numValues, v;
323 
324       ierr = DMPlexGetLabelName(dm, l, &name);CHKERRQ(ierr);
325       ierr = DMPlexGetLabel(dm, name, &label);CHKERRQ(ierr);
326       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
327       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);CHKERRQ(ierr);
328       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
329       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
330       for (v = 0; v < numValues; ++v) {
331         PetscInt size;
332 
333         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
334         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
335         ierr = PetscViewerASCIIPrintf(viewer, "%d", size);CHKERRQ(ierr);
336       }
337       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
338       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
339     }
340   }
341   PetscFunctionReturn(0);
342 }
343 
344 #undef __FUNCT__
345 #define __FUNCT__ "DMView_Plex"
346 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
347 {
348   PetscBool      iascii, isbinary;
349   PetscErrorCode ierr;
350 
351   PetscFunctionBegin;
352   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
353   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
354   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
355   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
356   if (iascii) {
357     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
358 #if 0
359   } else if (isbinary) {
360     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
361 #endif
362   }
363   PetscFunctionReturn(0);
364 }
365 
366 #undef __FUNCT__
367 #define __FUNCT__ "DMDestroy_Plex"
368 PetscErrorCode DMDestroy_Plex(DM dm)
369 {
370   DM_Plex       *mesh = (DM_Plex*) dm->data;
371   DMLabel        next  = mesh->labels;
372   PetscErrorCode ierr;
373 
374   PetscFunctionBegin;
375   if (--mesh->refct > 0) PetscFunctionReturn(0);
376   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
377   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
378   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
379   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
380   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
381   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
382   while (next) {
383     DMLabel tmp = next->next;
384 
385     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
386     next = tmp;
387   }
388   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
389   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
390   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
391   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
392   ierr = PetscFree(mesh);CHKERRQ(ierr);
393   PetscFunctionReturn(0);
394 }
395 
396 #undef __FUNCT__
397 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
398 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
399 {
400   const PetscInt *support = NULL;
401   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
402   PetscErrorCode  ierr;
403 
404   PetscFunctionBegin;
405   if (useClosure) {
406     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
407     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
408     for (s = 0; s < supportSize; ++s) {
409       const PetscInt *cone = NULL;
410       PetscInt        coneSize, c, q;
411 
412       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
413       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
414       for (c = 0; c < coneSize; ++c) {
415         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
416           if (cone[c] == adj[q]) break;
417         }
418         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
419       }
420     }
421   } else {
422     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
423     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
424     for (s = 0; s < supportSize; ++s) {
425       const PetscInt *cone = NULL;
426       PetscInt        coneSize, c, q;
427 
428       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
429       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
430       for (c = 0; c < coneSize; ++c) {
431         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
432           if (cone[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     }
437   }
438   *adjSize = numAdj;
439   PetscFunctionReturn(0);
440 }
441 
442 #undef __FUNCT__
443 #define __FUNCT__ "DMPlexGetAdjacency_Private"
444 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
445 {
446   const PetscInt *star  = tmpClosure;
447   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
448   PetscErrorCode  ierr;
449 
450   PetscFunctionBegin;
451   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
452   for (s = 2; s < starSize*2; s += 2) {
453     const PetscInt *closure = NULL;
454     PetscInt        closureSize, c, q;
455 
456     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
457     for (c = 0; c < closureSize*2; c += 2) {
458       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
459         if (closure[c] == adj[q]) break;
460       }
461       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
462     }
463     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
464   }
465   *adjSize = numAdj;
466   PetscFunctionReturn(0);
467 }
468 
469 #undef __FUNCT__
470 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
471 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
472 {
473   DM_Plex *mesh = (DM_Plex*) dm->data;
474 
475   PetscFunctionBegin;
476   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
477   mesh->preallocCenterDim = preallocCenterDim;
478   PetscFunctionReturn(0);
479 }
480 
481 #undef __FUNCT__
482 #define __FUNCT__ "DMPlexPreallocateOperator"
483 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
484 {
485   DM_Plex           *mesh = (DM_Plex*) dm->data;
486   MPI_Comm           comm;
487   PetscSF            sf, sfDof, sfAdj;
488   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
489   PetscInt           nleaves, l, p;
490   const PetscInt    *leaves;
491   const PetscSFNode *remotes;
492   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
493   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
494   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
495   PetscLayout        rLayout;
496   PetscInt           locRows, rStart, rEnd, r;
497   PetscMPIInt        size;
498   PetscBool          useClosure, debug = PETSC_FALSE;
499   PetscErrorCode     ierr;
500 
501   PetscFunctionBegin;
502   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
503   ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr);
504   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
505   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
506   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
507   /* Create dof SF based on point SF */
508   if (debug) {
509     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
510     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
511     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
512     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
513     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
514     ierr = PetscSFView(sf, NULL);CHKERRQ(ierr);
515   }
516   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
517   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
518   if (debug) {
519     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
520     ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr);
521   }
522   /* Create section for dof adjacency (dof ==> # adj dof) */
523   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
524   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
525   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
526   if (mesh->preallocCenterDim == dim) {
527     useClosure = PETSC_FALSE;
528   } else if (mesh->preallocCenterDim == 0) {
529     useClosure = PETSC_TRUE;
530   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
531 
532   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
533   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
534   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
535   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
536   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
537   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
538   /*   Fill in the ghost dofs on the interface */
539   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
540   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
541   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
542 
543   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
544   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
545 
546   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
547 
548   /*
549    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
550     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
551        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
552     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
553        Create sfAdj connecting rootSectionAdj and leafSectionAdj
554     3. Visit unowned points on interface, write adjacencies to adj
555        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
556     4. Visit owned points on interface, write adjacencies to rootAdj
557        Remove redundancy in rootAdj
558    ** The last two traversals use transitive closure
559     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
560        Allocate memory addressed by sectionAdj (cols)
561     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
562    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
563   */
564 
565   for (l = 0; l < nleaves; ++l) {
566     PetscInt dof, off, d, q;
567     PetscInt p = leaves[l], numAdj = maxAdjSize;
568 
569     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
570     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
571     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
572     for (q = 0; q < numAdj; ++q) {
573       const PetscInt padj = tmpAdj[q];
574       PetscInt ndof, ncdof;
575 
576       if ((padj < pStart) || (padj >= pEnd)) continue;
577       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
578       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
579       for (d = off; d < off+dof; ++d) {
580         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
581       }
582     }
583   }
584   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
585   if (debug) {
586     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
587     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
588   }
589   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
590   if (size > 1) {
591     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
592     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
593   }
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
596     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
597   }
598   /* Add in local adjacency sizes for owned dofs on interface (roots) */
599   for (p = pStart; p < pEnd; ++p) {
600     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
601 
602     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
603     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
604     if (!dof) continue;
605     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
606     if (adof <= 0) continue;
607     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
608     for (q = 0; q < numAdj; ++q) {
609       const PetscInt padj = tmpAdj[q];
610       PetscInt ndof, ncdof;
611 
612       if ((padj < pStart) || (padj >= pEnd)) continue;
613       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
614       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
615       for (d = off; d < off+dof; ++d) {
616         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
617       }
618     }
619   }
620   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
621   if (debug) {
622     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
623     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
624   }
625   /* Create adj SF based on dof SF */
626   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
627   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
628   if (debug) {
629     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
630     ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr);
631   }
632   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
633   /* Create leaf adjacency */
634   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
635   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
636   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
637   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
638   for (l = 0; l < nleaves; ++l) {
639     PetscInt dof, off, d, q;
640     PetscInt p = leaves[l], numAdj = maxAdjSize;
641 
642     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
643     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
644     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
645     for (d = off; d < off+dof; ++d) {
646       PetscInt aoff, i = 0;
647 
648       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
649       for (q = 0; q < numAdj; ++q) {
650         const PetscInt padj = tmpAdj[q];
651         PetscInt ndof, ncdof, ngoff, nd;
652 
653         if ((padj < pStart) || (padj >= pEnd)) continue;
654         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
655         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
656         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
657         for (nd = 0; nd < ndof-ncdof; ++nd) {
658           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
659           ++i;
660         }
661       }
662     }
663   }
664   /* Debugging */
665   if (debug) {
666     IS tmp;
667     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
668     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
669     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
670   }
671   /* Gather adjacenct indices to root */
672   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
673   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
674   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
675   if (size > 1) {
676     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
677     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
678   }
679   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
680   ierr = PetscFree(adj);CHKERRQ(ierr);
681   /* Debugging */
682   if (debug) {
683     IS tmp;
684     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
685     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
686     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
687   }
688   /* Add in local adjacency indices for owned dofs on interface (roots) */
689   for (p = pStart; p < pEnd; ++p) {
690     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
691 
692     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
693     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
694     if (!dof) continue;
695     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
696     if (adof <= 0) continue;
697     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
698     for (d = off; d < off+dof; ++d) {
699       PetscInt adof, aoff, i;
700 
701       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
702       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
703       i    = adof-1;
704       for (q = 0; q < numAdj; ++q) {
705         const PetscInt padj = tmpAdj[q];
706         PetscInt ndof, ncdof, ngoff, nd;
707 
708         if ((padj < pStart) || (padj >= pEnd)) continue;
709         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
710         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
711         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
712         for (nd = 0; nd < ndof-ncdof; ++nd) {
713           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
714           --i;
715         }
716       }
717     }
718   }
719   /* Debugging */
720   if (debug) {
721     IS tmp;
722     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
723     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
724     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
725   }
726   /* Compress indices */
727   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
728   for (p = pStart; p < pEnd; ++p) {
729     PetscInt dof, cdof, off, d;
730     PetscInt adof, aoff;
731 
732     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
733     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
734     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
735     if (!dof) continue;
736     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
737     if (adof <= 0) continue;
738     for (d = off; d < off+dof-cdof; ++d) {
739       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
740       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
741       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
742       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
743     }
744   }
745   /* Debugging */
746   if (debug) {
747     IS tmp;
748     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
749     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
750     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
751     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
752     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
753   }
754   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
755   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
756   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
757   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
758   for (p = pStart; p < pEnd; ++p) {
759     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
760     PetscBool found  = PETSC_TRUE;
761 
762     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
763     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
764     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
765     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
766     for (d = 0; d < dof-cdof; ++d) {
767       PetscInt ldof, rdof;
768 
769       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
770       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
771       if (ldof > 0) {
772         /* We do not own this point */
773       } else if (rdof > 0) {
774         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
775       } else {
776         found = PETSC_FALSE;
777       }
778     }
779     if (found) continue;
780     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
781     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
782     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
783     for (q = 0; q < numAdj; ++q) {
784       const PetscInt padj = tmpAdj[q];
785       PetscInt ndof, ncdof, noff;
786 
787       if ((padj < pStart) || (padj >= pEnd)) continue;
788       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
789       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
790       ierr = PetscSectionGetOffset(section, padj, &noff);CHKERRQ(ierr);
791       for (d = goff; d < goff+dof-cdof; ++d) {
792         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
793       }
794     }
795   }
796   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
797   if (debug) {
798     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
799     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
800   }
801   /* Get adjacent indices */
802   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
803   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
804   for (p = pStart; p < pEnd; ++p) {
805     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
806     PetscBool found  = PETSC_TRUE;
807 
808     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
809     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
810     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
811     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
812     for (d = 0; d < dof-cdof; ++d) {
813       PetscInt ldof, rdof;
814 
815       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
816       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
817       if (ldof > 0) {
818         /* We do not own this point */
819       } else if (rdof > 0) {
820         PetscInt aoff, roff;
821 
822         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
823         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
824         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
825       } else {
826         found = PETSC_FALSE;
827       }
828     }
829     if (found) continue;
830     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
831     for (d = goff; d < goff+dof-cdof; ++d) {
832       PetscInt adof, aoff, i = 0;
833 
834       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
835       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
836       for (q = 0; q < numAdj; ++q) {
837         const PetscInt  padj = tmpAdj[q];
838         PetscInt        ndof, ncdof, ngoff, nd;
839         const PetscInt *ncind;
840 
841         /* Adjacent points may not be in the section chart */
842         if ((padj < pStart) || (padj >= pEnd)) continue;
843         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
844         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
845         ierr = PetscSectionGetConstraintIndices(section, padj, &ncind);CHKERRQ(ierr);
846         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
847         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
848           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
849         }
850       }
851       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);
852     }
853   }
854   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
855   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
856   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
857   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
858   /* Debugging */
859   if (debug) {
860     IS tmp;
861     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
862     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
863     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
864   }
865   /* Create allocation vectors from adjacency graph */
866   ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr);
867   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr);
868   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
869   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
870   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
871   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
872   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
873   /* Only loop over blocks of rows */
874   if (rStart%bs || rEnd%bs) SETERRQ3(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
875   for (r = rStart/bs; r < rEnd/bs; ++r) {
876     const PetscInt row = r*bs;
877     PetscInt       numCols, cStart, c;
878 
879     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
880     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
881     for (c = cStart; c < cStart+numCols; ++c) {
882       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
883         ++dnz[r-rStart];
884         if (cols[c] >= row) ++dnzu[r-rStart];
885       } else {
886         ++onz[r-rStart];
887         if (cols[c] >= row) ++onzu[r-rStart];
888       }
889     }
890   }
891   if (bs > 1) {
892     for (r = 0; r < locRows/bs; ++r) {
893       dnz[r]  /= bs;
894       onz[r]  /= bs;
895       dnzu[r] /= bs;
896       onzu[r] /= bs;
897     }
898   }
899   /* Set matrix pattern */
900   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
901   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
902   /* Fill matrix with zeros */
903   if (fillMatrix) {
904     PetscScalar *values;
905     PetscInt     maxRowLen = 0;
906 
907     for (r = rStart; r < rEnd; ++r) {
908       PetscInt len;
909 
910       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
911       maxRowLen = PetscMax(maxRowLen, len);
912     }
913     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
914     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
915     for (r = rStart; r < rEnd; ++r) {
916       PetscInt numCols, cStart;
917 
918       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
919       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
920       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
921     }
922     ierr = PetscFree(values);CHKERRQ(ierr);
923     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
924     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
925   }
926   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
927   ierr = PetscFree(cols);CHKERRQ(ierr);
928   PetscFunctionReturn(0);
929 }
930 
931 #if 0
932 #undef __FUNCT__
933 #define __FUNCT__ "DMPlexPreallocateOperator_2"
934 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
935 {
936   PetscInt       *tmpClosure,*tmpAdj,*visits;
937   PetscInt        c,cStart,cEnd,pStart,pEnd;
938   PetscErrorCode  ierr;
939 
940   PetscFunctionBegin;
941   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
942   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
943   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
944 
945   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
946 
947   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
948   npoints = pEnd - pStart;
949 
950   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
951   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
952   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
953   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
954   for (c=cStart; c<cEnd; c++) {
955     PetscInt *support = tmpClosure;
956     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
957     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
958   }
959   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
960   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
961   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
962   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
963 
964   ierr = PetscSFGetRanks();CHKERRQ(ierr);
965 
966 
967   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
968   for (c=cStart; c<cEnd; c++) {
969     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
970     /*
971      Depth-first walk of transitive closure.
972      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.
973      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
974      */
975   }
976 
977   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
978   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
979   PetscFunctionReturn(0);
980 }
981 #endif
982 
983 #undef __FUNCT__
984 #define __FUNCT__ "DMCreateMatrix_Plex"
985 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
986 {
987   PetscSection   section, sectionGlobal;
988   PetscInt       bs = -1;
989   PetscInt       localSize;
990   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
991   PetscErrorCode ierr;
992 
993   PetscFunctionBegin;
994 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
995   ierr = MatInitializePackage(NULL);CHKERRQ(ierr);
996 #endif
997   if (!mtype) mtype = MATAIJ;
998   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
999   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1000   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
1001   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
1002   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
1003   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1004   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
1005   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
1006   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
1007   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
1008   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
1009   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
1010   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
1011   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
1012   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
1013   /* Check for symmetric storage */
1014   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
1015   if (isSymmetric) {
1016     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
1017   }
1018   if (!isShell) {
1019     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
1020     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
1021 
1022     if (bs < 0) {
1023       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
1024         PetscInt pStart, pEnd, p, dof, cdof;
1025 
1026         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1027         for (p = pStart; p < pEnd; ++p) {
1028           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
1029           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
1030           if (dof-cdof) {
1031             if (bs < 0) {
1032               bs = dof-cdof;
1033             } else if (bs != dof-cdof) {
1034               /* Layout does not admit a pointwise block size */
1035               bs = 1;
1036               break;
1037             }
1038           }
1039         }
1040         /* Must have same blocksize on all procs (some might have no points) */
1041         bsLocal = bs;
1042         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1043         bsLocal = bs < 0 ? bsMax : bs;
1044         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1045         if (bsMin != bsMax) {
1046           bs = 1;
1047         } else {
1048           bs = bsMax;
1049         }
1050       } else {
1051         bs = 1;
1052       }
1053     }
1054     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1055     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1056     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1057     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1058     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1059     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1060     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1061   }
1062   PetscFunctionReturn(0);
1063 }
1064 
1065 #undef __FUNCT__
1066 #define __FUNCT__ "DMPlexGetDimension"
1067 /*@
1068   DMPlexGetDimension - Return the topological mesh dimension
1069 
1070   Not collective
1071 
1072   Input Parameter:
1073 . mesh - The DMPlex
1074 
1075   Output Parameter:
1076 . dim - The topological mesh dimension
1077 
1078   Level: beginner
1079 
1080 .seealso: DMPlexCreate()
1081 @*/
1082 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1083 {
1084   DM_Plex *mesh = (DM_Plex*) dm->data;
1085 
1086   PetscFunctionBegin;
1087   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1088   PetscValidPointer(dim, 2);
1089   *dim = mesh->dim;
1090   PetscFunctionReturn(0);
1091 }
1092 
1093 #undef __FUNCT__
1094 #define __FUNCT__ "DMPlexSetDimension"
1095 /*@
1096   DMPlexSetDimension - Set the topological mesh dimension
1097 
1098   Collective on mesh
1099 
1100   Input Parameters:
1101 + mesh - The DMPlex
1102 - dim - The topological mesh dimension
1103 
1104   Level: beginner
1105 
1106 .seealso: DMPlexCreate()
1107 @*/
1108 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1109 {
1110   DM_Plex *mesh = (DM_Plex*) dm->data;
1111 
1112   PetscFunctionBegin;
1113   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1114   PetscValidLogicalCollectiveInt(dm, dim, 2);
1115   mesh->dim               = dim;
1116   mesh->preallocCenterDim = dim;
1117   PetscFunctionReturn(0);
1118 }
1119 
1120 #undef __FUNCT__
1121 #define __FUNCT__ "DMPlexGetChart"
1122 /*@
1123   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1124 
1125   Not collective
1126 
1127   Input Parameter:
1128 . mesh - The DMPlex
1129 
1130   Output Parameters:
1131 + pStart - The first mesh point
1132 - pEnd   - The upper bound for mesh points
1133 
1134   Level: beginner
1135 
1136 .seealso: DMPlexCreate(), DMPlexSetChart()
1137 @*/
1138 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1139 {
1140   DM_Plex       *mesh = (DM_Plex*) dm->data;
1141   PetscErrorCode ierr;
1142 
1143   PetscFunctionBegin;
1144   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1145   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1146   PetscFunctionReturn(0);
1147 }
1148 
1149 #undef __FUNCT__
1150 #define __FUNCT__ "DMPlexSetChart"
1151 /*@
1152   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1153 
1154   Not collective
1155 
1156   Input Parameters:
1157 + mesh - The DMPlex
1158 . pStart - The first mesh point
1159 - pEnd   - The upper bound for mesh points
1160 
1161   Output Parameters:
1162 
1163   Level: beginner
1164 
1165 .seealso: DMPlexCreate(), DMPlexGetChart()
1166 @*/
1167 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1168 {
1169   DM_Plex       *mesh = (DM_Plex*) dm->data;
1170   PetscErrorCode ierr;
1171 
1172   PetscFunctionBegin;
1173   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1174   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1175   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1176   PetscFunctionReturn(0);
1177 }
1178 
1179 #undef __FUNCT__
1180 #define __FUNCT__ "DMPlexGetConeSize"
1181 /*@
1182   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1183 
1184   Not collective
1185 
1186   Input Parameters:
1187 + mesh - The DMPlex
1188 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1189 
1190   Output Parameter:
1191 . size - The cone size for point p
1192 
1193   Level: beginner
1194 
1195 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1196 @*/
1197 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1198 {
1199   DM_Plex       *mesh = (DM_Plex*) dm->data;
1200   PetscErrorCode ierr;
1201 
1202   PetscFunctionBegin;
1203   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1204   PetscValidPointer(size, 3);
1205   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1206   PetscFunctionReturn(0);
1207 }
1208 
1209 #undef __FUNCT__
1210 #define __FUNCT__ "DMPlexSetConeSize"
1211 /*@
1212   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1213 
1214   Not collective
1215 
1216   Input Parameters:
1217 + mesh - The DMPlex
1218 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1219 - size - The cone size for point p
1220 
1221   Output Parameter:
1222 
1223   Note:
1224   This should be called after DMPlexSetChart().
1225 
1226   Level: beginner
1227 
1228 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1229 @*/
1230 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1231 {
1232   DM_Plex       *mesh = (DM_Plex*) dm->data;
1233   PetscErrorCode ierr;
1234 
1235   PetscFunctionBegin;
1236   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1237   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1238 
1239   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1240   PetscFunctionReturn(0);
1241 }
1242 
1243 #undef __FUNCT__
1244 #define __FUNCT__ "DMPlexGetCone"
1245 /*@C
1246   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1247 
1248   Not collective
1249 
1250   Input Parameters:
1251 + mesh - The DMPlex
1252 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1253 
1254   Output Parameter:
1255 . cone - An array of points which are on the in-edges for point p
1256 
1257   Level: beginner
1258 
1259   Note:
1260   This routine is not available in Fortran.
1261 
1262 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1263 @*/
1264 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1265 {
1266   DM_Plex       *mesh = (DM_Plex*) dm->data;
1267   PetscInt       off;
1268   PetscErrorCode ierr;
1269 
1270   PetscFunctionBegin;
1271   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1272   PetscValidPointer(cone, 3);
1273   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1274   *cone = &mesh->cones[off];
1275   PetscFunctionReturn(0);
1276 }
1277 
1278 #undef __FUNCT__
1279 #define __FUNCT__ "DMPlexSetCone"
1280 /*@
1281   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1282 
1283   Not collective
1284 
1285   Input Parameters:
1286 + mesh - The DMPlex
1287 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1288 - cone - An array of points which are on the in-edges for point p
1289 
1290   Output Parameter:
1291 
1292   Note:
1293   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1294 
1295   Level: beginner
1296 
1297 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1298 @*/
1299 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1300 {
1301   DM_Plex       *mesh = (DM_Plex*) dm->data;
1302   PetscInt       pStart, pEnd;
1303   PetscInt       dof, off, c;
1304   PetscErrorCode ierr;
1305 
1306   PetscFunctionBegin;
1307   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1308   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1309   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1310   if (dof) PetscValidPointer(cone, 3);
1311   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1312   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1313   for (c = 0; c < dof; ++c) {
1314     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1315     mesh->cones[off+c] = cone[c];
1316   }
1317   PetscFunctionReturn(0);
1318 }
1319 
1320 #undef __FUNCT__
1321 #define __FUNCT__ "DMPlexGetConeOrientation"
1322 /*@C
1323   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1324 
1325   Not collective
1326 
1327   Input Parameters:
1328 + mesh - The DMPlex
1329 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1330 
1331   Output Parameter:
1332 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1333                     integer giving the prescription for cone traversal. If it is negative, the cone is
1334                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1335                     the index of the cone point on which to start.
1336 
1337   Level: beginner
1338 
1339   Note:
1340   This routine is not available in Fortran.
1341 
1342 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1343 @*/
1344 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1345 {
1346   DM_Plex       *mesh = (DM_Plex*) dm->data;
1347   PetscInt       off;
1348   PetscErrorCode ierr;
1349 
1350   PetscFunctionBegin;
1351   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1352 #if defined(PETSC_USE_DEBUG)
1353   {
1354     PetscInt dof;
1355     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1356     if (dof) PetscValidPointer(coneOrientation, 3);
1357   }
1358 #endif
1359   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1360 
1361   *coneOrientation = &mesh->coneOrientations[off];
1362   PetscFunctionReturn(0);
1363 }
1364 
1365 #undef __FUNCT__
1366 #define __FUNCT__ "DMPlexSetConeOrientation"
1367 /*@
1368   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1369 
1370   Not collective
1371 
1372   Input Parameters:
1373 + mesh - The DMPlex
1374 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1375 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1376                     integer giving the prescription for cone traversal. If it is negative, the cone is
1377                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1378                     the index of the cone point on which to start.
1379 
1380   Output Parameter:
1381 
1382   Note:
1383   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1384 
1385   Level: beginner
1386 
1387 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1388 @*/
1389 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1390 {
1391   DM_Plex       *mesh = (DM_Plex*) dm->data;
1392   PetscInt       pStart, pEnd;
1393   PetscInt       dof, off, c;
1394   PetscErrorCode ierr;
1395 
1396   PetscFunctionBegin;
1397   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1398   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1399   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1400   if (dof) PetscValidPointer(coneOrientation, 3);
1401   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1402   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1403   for (c = 0; c < dof; ++c) {
1404     PetscInt cdof, o = coneOrientation[c];
1405 
1406     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1407     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1408     mesh->coneOrientations[off+c] = o;
1409   }
1410   PetscFunctionReturn(0);
1411 }
1412 
1413 #undef __FUNCT__
1414 #define __FUNCT__ "DMPlexInsertCone"
1415 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1416 {
1417   DM_Plex       *mesh = (DM_Plex*) dm->data;
1418   PetscInt       pStart, pEnd;
1419   PetscInt       dof, off;
1420   PetscErrorCode ierr;
1421 
1422   PetscFunctionBegin;
1423   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1424   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1425   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1426   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1427   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1428   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1429   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1430   mesh->cones[off+conePos] = conePoint;
1431   PetscFunctionReturn(0);
1432 }
1433 
1434 #undef __FUNCT__
1435 #define __FUNCT__ "DMPlexInsertConeOrientation"
1436 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1437 {
1438   DM_Plex       *mesh = (DM_Plex*) dm->data;
1439   PetscInt       pStart, pEnd;
1440   PetscInt       dof, off;
1441   PetscErrorCode ierr;
1442 
1443   PetscFunctionBegin;
1444   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1445   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1446   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1447   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1448   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1449   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1450   mesh->coneOrientations[off+conePos] = coneOrientation;
1451   PetscFunctionReturn(0);
1452 }
1453 
1454 #undef __FUNCT__
1455 #define __FUNCT__ "DMPlexGetSupportSize"
1456 /*@
1457   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1458 
1459   Not collective
1460 
1461   Input Parameters:
1462 + mesh - The DMPlex
1463 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1464 
1465   Output Parameter:
1466 . size - The support size for point p
1467 
1468   Level: beginner
1469 
1470 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1471 @*/
1472 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1473 {
1474   DM_Plex       *mesh = (DM_Plex*) dm->data;
1475   PetscErrorCode ierr;
1476 
1477   PetscFunctionBegin;
1478   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1479   PetscValidPointer(size, 3);
1480   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1481   PetscFunctionReturn(0);
1482 }
1483 
1484 #undef __FUNCT__
1485 #define __FUNCT__ "DMPlexSetSupportSize"
1486 /*@
1487   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1488 
1489   Not collective
1490 
1491   Input Parameters:
1492 + mesh - The DMPlex
1493 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1494 - size - The support size for point p
1495 
1496   Output Parameter:
1497 
1498   Note:
1499   This should be called after DMPlexSetChart().
1500 
1501   Level: beginner
1502 
1503 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1504 @*/
1505 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1506 {
1507   DM_Plex       *mesh = (DM_Plex*) dm->data;
1508   PetscErrorCode ierr;
1509 
1510   PetscFunctionBegin;
1511   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1512   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1513 
1514   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1515   PetscFunctionReturn(0);
1516 }
1517 
1518 #undef __FUNCT__
1519 #define __FUNCT__ "DMPlexGetSupport"
1520 /*@C
1521   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1522 
1523   Not collective
1524 
1525   Input Parameters:
1526 + mesh - The DMPlex
1527 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1528 
1529   Output Parameter:
1530 . support - An array of points which are on the out-edges for point p
1531 
1532   Level: beginner
1533 
1534 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1535 @*/
1536 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1537 {
1538   DM_Plex       *mesh = (DM_Plex*) dm->data;
1539   PetscInt       off;
1540   PetscErrorCode ierr;
1541 
1542   PetscFunctionBegin;
1543   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1544   PetscValidPointer(support, 3);
1545   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1546   *support = &mesh->supports[off];
1547   PetscFunctionReturn(0);
1548 }
1549 
1550 #undef __FUNCT__
1551 #define __FUNCT__ "DMPlexSetSupport"
1552 /*@
1553   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1554 
1555   Not collective
1556 
1557   Input Parameters:
1558 + mesh - The DMPlex
1559 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1560 - support - An array of points which are on the in-edges for point p
1561 
1562   Output Parameter:
1563 
1564   Note:
1565   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1566 
1567   Level: beginner
1568 
1569 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1570 @*/
1571 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1572 {
1573   DM_Plex       *mesh = (DM_Plex*) dm->data;
1574   PetscInt       pStart, pEnd;
1575   PetscInt       dof, off, c;
1576   PetscErrorCode ierr;
1577 
1578   PetscFunctionBegin;
1579   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1580   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1581   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1582   if (dof) PetscValidPointer(support, 3);
1583   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1584   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1585   for (c = 0; c < dof; ++c) {
1586     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1587     mesh->supports[off+c] = support[c];
1588   }
1589   PetscFunctionReturn(0);
1590 }
1591 
1592 #undef __FUNCT__
1593 #define __FUNCT__ "DMPlexInsertSupport"
1594 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1595 {
1596   DM_Plex       *mesh = (DM_Plex*) dm->data;
1597   PetscInt       pStart, pEnd;
1598   PetscInt       dof, off;
1599   PetscErrorCode ierr;
1600 
1601   PetscFunctionBegin;
1602   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1603   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1604   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1605   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1606   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1607   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1608   if (supportPos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1609   mesh->supports[off+supportPos] = supportPoint;
1610   PetscFunctionReturn(0);
1611 }
1612 
1613 #undef __FUNCT__
1614 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1615 /*@C
1616   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1617 
1618   Not collective
1619 
1620   Input Parameters:
1621 + mesh - The DMPlex
1622 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1623 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1624 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1625 
1626   Output Parameters:
1627 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1628 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1629 
1630   Note:
1631   If using internal storage (points is NULL on input), each call overwrites the last output.
1632 
1633   Level: beginner
1634 
1635 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1636 @*/
1637 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1638 {
1639   DM_Plex        *mesh = (DM_Plex*) dm->data;
1640   PetscInt       *closure, *fifo;
1641   const PetscInt *tmp = NULL, *tmpO = NULL;
1642   PetscInt        tmpSize, t;
1643   PetscInt        depth       = 0, maxSize;
1644   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1645   PetscErrorCode  ierr;
1646 
1647   PetscFunctionBegin;
1648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1649   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1650   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1651   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1652   if (*points) {
1653     closure = *points;
1654   } else {
1655     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1656   }
1657   closure[0] = p; closure[1] = 0;
1658   /* This is only 1-level */
1659   if (useCone) {
1660     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1661     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1662     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1663   } else {
1664     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1665     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1666   }
1667   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1668     const PetscInt cp = tmp[t];
1669     const PetscInt co = tmpO ? tmpO[t] : 0;
1670 
1671     closure[closureSize]   = cp;
1672     closure[closureSize+1] = co;
1673     fifo[fifoSize]         = cp;
1674     fifo[fifoSize+1]       = co;
1675   }
1676   while (fifoSize - fifoStart) {
1677     const PetscInt q   = fifo[fifoStart];
1678     const PetscInt o   = fifo[fifoStart+1];
1679     const PetscInt rev = o >= 0 ? 0 : 1;
1680     const PetscInt off = rev ? -(o+1) : o;
1681 
1682     if (useCone) {
1683       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1684       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1685       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1686     } else {
1687       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1688       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1689       tmpO = NULL;
1690     }
1691     for (t = 0; t < tmpSize; ++t) {
1692       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1693       const PetscInt cp = tmp[i];
1694       /* Must propogate orientation */
1695       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1696       PetscInt       c;
1697 
1698       /* Check for duplicate */
1699       for (c = 0; c < closureSize; c += 2) {
1700         if (closure[c] == cp) break;
1701       }
1702       if (c == closureSize) {
1703         closure[closureSize]   = cp;
1704         closure[closureSize+1] = co;
1705         fifo[fifoSize]         = cp;
1706         fifo[fifoSize+1]       = co;
1707         closureSize           += 2;
1708         fifoSize              += 2;
1709       }
1710     }
1711     fifoStart += 2;
1712   }
1713   if (numPoints) *numPoints = closureSize/2;
1714   if (points)    *points    = closure;
1715   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1716   PetscFunctionReturn(0);
1717 }
1718 
1719 #undef __FUNCT__
1720 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1721 /*@C
1722   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1723 
1724   Not collective
1725 
1726   Input Parameters:
1727 + mesh - The DMPlex
1728 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1729 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1730 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1731 
1732   Output Parameters:
1733 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1734 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1735 
1736   Note:
1737   If not using internal storage (points is not NULL on input), this call is unnecessary
1738 
1739   Level: beginner
1740 
1741 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1742 @*/
1743 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1744 {
1745   PetscErrorCode ierr;
1746 
1747   PetscFunctionBegin;
1748   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1749   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1750   PetscFunctionReturn(0);
1751 }
1752 
1753 #undef __FUNCT__
1754 #define __FUNCT__ "DMPlexGetMaxSizes"
1755 /*@
1756   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1757 
1758   Not collective
1759 
1760   Input Parameter:
1761 . mesh - The DMPlex
1762 
1763   Output Parameters:
1764 + maxConeSize - The maximum number of in-edges
1765 - maxSupportSize - The maximum number of out-edges
1766 
1767   Level: beginner
1768 
1769 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1770 @*/
1771 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1772 {
1773   DM_Plex *mesh = (DM_Plex*) dm->data;
1774 
1775   PetscFunctionBegin;
1776   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1777   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1778   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1779   PetscFunctionReturn(0);
1780 }
1781 
1782 #undef __FUNCT__
1783 #define __FUNCT__ "DMSetUp_Plex"
1784 PetscErrorCode DMSetUp_Plex(DM dm)
1785 {
1786   DM_Plex       *mesh = (DM_Plex*) dm->data;
1787   PetscInt       size;
1788   PetscErrorCode ierr;
1789 
1790   PetscFunctionBegin;
1791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1792   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1793   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1794   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1795   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1796   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1797   if (mesh->maxSupportSize) {
1798     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1799     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1800     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1801   }
1802   PetscFunctionReturn(0);
1803 }
1804 
1805 #undef __FUNCT__
1806 #define __FUNCT__ "DMCreateSubDM_Plex"
1807 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1808 {
1809   PetscSection   section, sectionGlobal;
1810   PetscInt      *subIndices;
1811   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1812   PetscErrorCode ierr;
1813 
1814   PetscFunctionBegin;
1815   if (!numFields) PetscFunctionReturn(0);
1816   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1817   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1818   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1819   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1820   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1821   if (numFields > nF) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1822   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1823   for (p = pStart; p < pEnd; ++p) {
1824     PetscInt gdof;
1825 
1826     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1827     if (gdof > 0) {
1828       for (f = 0; f < numFields; ++f) {
1829         PetscInt fdof, fcdof;
1830 
1831         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1832         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1833         subSize += fdof-fcdof;
1834       }
1835     }
1836   }
1837   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1838   for (p = pStart; p < pEnd; ++p) {
1839     PetscInt gdof, goff;
1840 
1841     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1842     if (gdof > 0) {
1843       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1844       for (f = 0; f < numFields; ++f) {
1845         PetscInt fdof, fcdof, fc, f2, poff = 0;
1846 
1847         /* Can get rid of this loop by storing field information in the global section */
1848         for (f2 = 0; f2 < fields[f]; ++f2) {
1849           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1850           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1851           poff += fdof-fcdof;
1852         }
1853         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1854         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1855         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1856           subIndices[subOff] = goff+poff+fc;
1857         }
1858       }
1859     }
1860   }
1861   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1862   if (subdm) {
1863     PetscSection subsection;
1864     PetscBool    haveNull = PETSC_FALSE;
1865     PetscInt     f, nf = 0;
1866 
1867     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1868     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1869     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1870     ierr = PetscSectionDestroy(&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(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
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(PetscObjectComm((PetscObject)dm), 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 
1953     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1954   }
1955   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1956   /* Calculate supports */
1957   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1958   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1959   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1960   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1961   for (p = pStart; p < pEnd; ++p) {
1962     PetscInt dof, off, c;
1963 
1964     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1965     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1966     for (c = off; c < off+dof; ++c) {
1967       const PetscInt q = mesh->cones[c];
1968       PetscInt       offS;
1969 
1970       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1971 
1972       mesh->supports[offS+offsets[q]] = p;
1973       ++offsets[q];
1974     }
1975   }
1976   ierr = PetscFree(offsets);CHKERRQ(ierr);
1977   PetscFunctionReturn(0);
1978 }
1979 
1980 #undef __FUNCT__
1981 #define __FUNCT__ "DMPlexSetDepth_Private"
1982 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1983 {
1984   PetscInt       d;
1985   PetscErrorCode ierr;
1986 
1987   PetscFunctionBegin;
1988   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1989   if (d < 0) {
1990     /* We are guaranteed that the point has a cone since the depth was not yet set */
1991     const PetscInt *cone = NULL;
1992     PetscInt        dCone;
1993 
1994     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1995     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1996     d    = dCone+1;
1997     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1998   }
1999   *depth = d;
2000   PetscFunctionReturn(0);
2001 }
2002 
2003 #undef __FUNCT__
2004 #define __FUNCT__ "DMPlexStratify"
2005 /*@
2006   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2007   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2008   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2009   the DAG.
2010 
2011   Not collective
2012 
2013   Input Parameter:
2014 . mesh - The DMPlex
2015 
2016   Output Parameter:
2017 
2018   Notes:
2019   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2020   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2021 
2022   This should be called after all calls to DMPlexSymmetrize()
2023 
2024   Level: beginner
2025 
2026 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2027 @*/
2028 PetscErrorCode DMPlexStratify(DM dm)
2029 {
2030   DM_Plex       *mesh = (DM_Plex*) dm->data;
2031   PetscInt       pStart, pEnd, p;
2032   PetscInt       numRoots = 0, numLeaves = 0;
2033   PetscErrorCode ierr;
2034 
2035   PetscFunctionBegin;
2036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2037   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2038   /* Calculate depth */
2039   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2040   /* Initialize roots and count leaves */
2041   for (p = pStart; p < pEnd; ++p) {
2042     PetscInt coneSize, supportSize;
2043 
2044     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2045     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2046     if (!coneSize && supportSize) {
2047       ++numRoots;
2048       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2049     } else if (!supportSize && coneSize) {
2050       ++numLeaves;
2051     } else if (!supportSize && !coneSize) {
2052       /* Isolated points */
2053       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2054     }
2055   }
2056   if (numRoots + numLeaves == (pEnd - pStart)) {
2057     for (p = pStart; p < pEnd; ++p) {
2058       PetscInt coneSize, supportSize;
2059 
2060       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2061       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2062       if (!supportSize && coneSize) {
2063         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2064       }
2065     }
2066   } else {
2067     /* This might be slow since lookup is not fast */
2068     for (p = pStart; p < pEnd; ++p) {
2069       PetscInt depth;
2070 
2071       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2072     }
2073   }
2074   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2075   PetscFunctionReturn(0);
2076 }
2077 
2078 #undef __FUNCT__
2079 #define __FUNCT__ "DMPlexGetJoin"
2080 /*@C
2081   DMPlexGetJoin - Get an array for the join of the set of points
2082 
2083   Not Collective
2084 
2085   Input Parameters:
2086 + dm - The DMPlex object
2087 . numPoints - The number of input points for the join
2088 - points - The input points
2089 
2090   Output Parameters:
2091 + numCoveredPoints - The number of points in the join
2092 - coveredPoints - The points in the join
2093 
2094   Level: intermediate
2095 
2096   Note: Currently, this is restricted to a single level join
2097 
2098 .keywords: mesh
2099 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2100 @*/
2101 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2102 {
2103   DM_Plex       *mesh = (DM_Plex*) dm->data;
2104   PetscInt      *join[2];
2105   PetscInt       joinSize, i = 0;
2106   PetscInt       dof, off, p, c, m;
2107   PetscErrorCode ierr;
2108 
2109   PetscFunctionBegin;
2110   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2111   PetscValidPointer(points, 2);
2112   PetscValidPointer(numCoveredPoints, 3);
2113   PetscValidPointer(coveredPoints, 4);
2114   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2115   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2116   /* Copy in support of first point */
2117   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2118   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2119   for (joinSize = 0; joinSize < dof; ++joinSize) {
2120     join[i][joinSize] = mesh->supports[off+joinSize];
2121   }
2122   /* Check each successive support */
2123   for (p = 1; p < numPoints; ++p) {
2124     PetscInt newJoinSize = 0;
2125 
2126     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2127     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2128     for (c = 0; c < dof; ++c) {
2129       const PetscInt point = mesh->supports[off+c];
2130 
2131       for (m = 0; m < joinSize; ++m) {
2132         if (point == join[i][m]) {
2133           join[1-i][newJoinSize++] = point;
2134           break;
2135         }
2136       }
2137     }
2138     joinSize = newJoinSize;
2139     i        = 1-i;
2140   }
2141   *numCoveredPoints = joinSize;
2142   *coveredPoints    = join[i];
2143   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2144   PetscFunctionReturn(0);
2145 }
2146 
2147 #undef __FUNCT__
2148 #define __FUNCT__ "DMPlexRestoreJoin"
2149 /*@C
2150   DMPlexRestoreJoin - Restore an array for the join of the set of points
2151 
2152   Not Collective
2153 
2154   Input Parameters:
2155 + dm - The DMPlex object
2156 . numPoints - The number of input points for the join
2157 - points - The input points
2158 
2159   Output Parameters:
2160 + numCoveredPoints - The number of points in the join
2161 - coveredPoints - The points in the join
2162 
2163   Level: intermediate
2164 
2165 .keywords: mesh
2166 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2167 @*/
2168 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2169 {
2170   PetscErrorCode ierr;
2171 
2172   PetscFunctionBegin;
2173   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2174   PetscValidPointer(coveredPoints, 4);
2175   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2176   PetscFunctionReturn(0);
2177 }
2178 
2179 #undef __FUNCT__
2180 #define __FUNCT__ "DMPlexGetFullJoin"
2181 /*@C
2182   DMPlexGetFullJoin - Get an array for the join of the set of points
2183 
2184   Not Collective
2185 
2186   Input Parameters:
2187 + dm - The DMPlex object
2188 . numPoints - The number of input points for the join
2189 - points - The input points
2190 
2191   Output Parameters:
2192 + numCoveredPoints - The number of points in the join
2193 - coveredPoints - The points in the join
2194 
2195   Level: intermediate
2196 
2197 .keywords: mesh
2198 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2199 @*/
2200 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2201 {
2202   DM_Plex       *mesh = (DM_Plex*) dm->data;
2203   PetscInt      *offsets, **closures;
2204   PetscInt      *join[2];
2205   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2206   PetscInt       p, d, c, m;
2207   PetscErrorCode ierr;
2208 
2209   PetscFunctionBegin;
2210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2211   PetscValidPointer(points, 2);
2212   PetscValidPointer(numCoveredPoints, 3);
2213   PetscValidPointer(coveredPoints, 4);
2214 
2215   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2216   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2217   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2218   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2219   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2220   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2221   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2222 
2223   for (p = 0; p < numPoints; ++p) {
2224     PetscInt closureSize;
2225 
2226     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2227 
2228     offsets[p*(depth+2)+0] = 0;
2229     for (d = 0; d < depth+1; ++d) {
2230       PetscInt pStart, pEnd, i;
2231 
2232       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2233       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2234         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2235           offsets[p*(depth+2)+d+1] = i;
2236           break;
2237         }
2238       }
2239       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2240     }
2241     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2242   }
2243   for (d = 0; d < depth+1; ++d) {
2244     PetscInt dof;
2245 
2246     /* Copy in support of first point */
2247     dof = offsets[d+1] - offsets[d];
2248     for (joinSize = 0; joinSize < dof; ++joinSize) {
2249       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2250     }
2251     /* Check each successive cone */
2252     for (p = 1; p < numPoints && joinSize; ++p) {
2253       PetscInt newJoinSize = 0;
2254 
2255       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2256       for (c = 0; c < dof; ++c) {
2257         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2258 
2259         for (m = 0; m < joinSize; ++m) {
2260           if (point == join[i][m]) {
2261             join[1-i][newJoinSize++] = point;
2262             break;
2263           }
2264         }
2265       }
2266       joinSize = newJoinSize;
2267       i        = 1-i;
2268     }
2269     if (joinSize) break;
2270   }
2271   *numCoveredPoints = joinSize;
2272   *coveredPoints    = join[i];
2273   for (p = 0; p < numPoints; ++p) {
2274     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2275   }
2276   ierr = PetscFree(closures);CHKERRQ(ierr);
2277   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2278   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2279   PetscFunctionReturn(0);
2280 }
2281 
2282 #undef __FUNCT__
2283 #define __FUNCT__ "DMPlexGetMeet"
2284 /*@C
2285   DMPlexGetMeet - Get an array for the meet of the set of points
2286 
2287   Not Collective
2288 
2289   Input Parameters:
2290 + dm - The DMPlex object
2291 . numPoints - The number of input points for the meet
2292 - points - The input points
2293 
2294   Output Parameters:
2295 + numCoveredPoints - The number of points in the meet
2296 - coveredPoints - The points in the meet
2297 
2298   Level: intermediate
2299 
2300   Note: Currently, this is restricted to a single level meet
2301 
2302 .keywords: mesh
2303 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2304 @*/
2305 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2306 {
2307   DM_Plex       *mesh = (DM_Plex*) dm->data;
2308   PetscInt      *meet[2];
2309   PetscInt       meetSize, i = 0;
2310   PetscInt       dof, off, p, c, m;
2311   PetscErrorCode ierr;
2312 
2313   PetscFunctionBegin;
2314   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2315   PetscValidPointer(points, 2);
2316   PetscValidPointer(numCoveringPoints, 3);
2317   PetscValidPointer(coveringPoints, 4);
2318   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2319   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2320   /* Copy in cone of first point */
2321   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2322   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2323   for (meetSize = 0; meetSize < dof; ++meetSize) {
2324     meet[i][meetSize] = mesh->cones[off+meetSize];
2325   }
2326   /* Check each successive cone */
2327   for (p = 1; p < numPoints; ++p) {
2328     PetscInt newMeetSize = 0;
2329 
2330     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2331     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2332     for (c = 0; c < dof; ++c) {
2333       const PetscInt point = mesh->cones[off+c];
2334 
2335       for (m = 0; m < meetSize; ++m) {
2336         if (point == meet[i][m]) {
2337           meet[1-i][newMeetSize++] = point;
2338           break;
2339         }
2340       }
2341     }
2342     meetSize = newMeetSize;
2343     i        = 1-i;
2344   }
2345   *numCoveringPoints = meetSize;
2346   *coveringPoints    = meet[i];
2347   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2348   PetscFunctionReturn(0);
2349 }
2350 
2351 #undef __FUNCT__
2352 #define __FUNCT__ "DMPlexRestoreMeet"
2353 /*@C
2354   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2355 
2356   Not Collective
2357 
2358   Input Parameters:
2359 + dm - The DMPlex object
2360 . numPoints - The number of input points for the meet
2361 - points - The input points
2362 
2363   Output Parameters:
2364 + numCoveredPoints - The number of points in the meet
2365 - coveredPoints - The points in the meet
2366 
2367   Level: intermediate
2368 
2369 .keywords: mesh
2370 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2371 @*/
2372 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2373 {
2374   PetscErrorCode ierr;
2375 
2376   PetscFunctionBegin;
2377   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2378   PetscValidPointer(coveredPoints, 4);
2379   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2380   PetscFunctionReturn(0);
2381 }
2382 
2383 #undef __FUNCT__
2384 #define __FUNCT__ "DMPlexGetFullMeet"
2385 /*@C
2386   DMPlexGetFullMeet - Get an array for the meet of the set of points
2387 
2388   Not Collective
2389 
2390   Input Parameters:
2391 + dm - The DMPlex object
2392 . numPoints - The number of input points for the meet
2393 - points - The input points
2394 
2395   Output Parameters:
2396 + numCoveredPoints - The number of points in the meet
2397 - coveredPoints - The points in the meet
2398 
2399   Level: intermediate
2400 
2401 .keywords: mesh
2402 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2403 @*/
2404 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2405 {
2406   DM_Plex       *mesh = (DM_Plex*) dm->data;
2407   PetscInt      *offsets, **closures;
2408   PetscInt      *meet[2];
2409   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2410   PetscInt       p, h, c, m;
2411   PetscErrorCode ierr;
2412 
2413   PetscFunctionBegin;
2414   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2415   PetscValidPointer(points, 2);
2416   PetscValidPointer(numCoveredPoints, 3);
2417   PetscValidPointer(coveredPoints, 4);
2418 
2419   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2420   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2421   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2422   maxSize = PetscPowInt(mesh->maxConeSize,height);
2423   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2424   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2425 
2426   for (p = 0; p < numPoints; ++p) {
2427     PetscInt closureSize;
2428 
2429     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2430 
2431     offsets[p*(height+2)+0] = 0;
2432     for (h = 0; h < height+1; ++h) {
2433       PetscInt pStart, pEnd, i;
2434 
2435       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2436       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2437         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2438           offsets[p*(height+2)+h+1] = i;
2439           break;
2440         }
2441       }
2442       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2443     }
2444     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2445   }
2446   for (h = 0; h < height+1; ++h) {
2447     PetscInt dof;
2448 
2449     /* Copy in cone of first point */
2450     dof = offsets[h+1] - offsets[h];
2451     for (meetSize = 0; meetSize < dof; ++meetSize) {
2452       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2453     }
2454     /* Check each successive cone */
2455     for (p = 1; p < numPoints && meetSize; ++p) {
2456       PetscInt newMeetSize = 0;
2457 
2458       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2459       for (c = 0; c < dof; ++c) {
2460         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2461 
2462         for (m = 0; m < meetSize; ++m) {
2463           if (point == meet[i][m]) {
2464             meet[1-i][newMeetSize++] = point;
2465             break;
2466           }
2467         }
2468       }
2469       meetSize = newMeetSize;
2470       i        = 1-i;
2471     }
2472     if (meetSize) break;
2473   }
2474   *numCoveredPoints = meetSize;
2475   *coveredPoints    = meet[i];
2476   for (p = 0; p < numPoints; ++p) {
2477     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2478   }
2479   ierr = PetscFree(closures);CHKERRQ(ierr);
2480   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2481   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2482   PetscFunctionReturn(0);
2483 }
2484 
2485 #undef __FUNCT__
2486 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2487 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2488 {
2489   MPI_Comm       comm;
2490   PetscErrorCode ierr;
2491 
2492   PetscFunctionBegin;
2493   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2494   PetscValidPointer(numFaceVertices,3);
2495   switch (cellDim) {
2496   case 0:
2497     *numFaceVertices = 0;
2498     break;
2499   case 1:
2500     *numFaceVertices = 1;
2501     break;
2502   case 2:
2503     switch (numCorners) {
2504     case 3: /* triangle */
2505       *numFaceVertices = 2; /* Edge has 2 vertices */
2506       break;
2507     case 4: /* quadrilateral */
2508       *numFaceVertices = 2; /* Edge has 2 vertices */
2509       break;
2510     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2511       *numFaceVertices = 3; /* Edge has 3 vertices */
2512       break;
2513     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2514       *numFaceVertices = 3; /* Edge has 3 vertices */
2515       break;
2516     default:
2517       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2518     }
2519     break;
2520   case 3:
2521     switch (numCorners) {
2522     case 4: /* tetradehdron */
2523       *numFaceVertices = 3; /* Face has 3 vertices */
2524       break;
2525     case 6: /* tet cohesive cells */
2526       *numFaceVertices = 4; /* Face has 4 vertices */
2527       break;
2528     case 8: /* hexahedron */
2529       *numFaceVertices = 4; /* Face has 4 vertices */
2530       break;
2531     case 9: /* tet cohesive Lagrange cells */
2532       *numFaceVertices = 6; /* Face has 6 vertices */
2533       break;
2534     case 10: /* quadratic tetrahedron */
2535       *numFaceVertices = 6; /* Face has 6 vertices */
2536       break;
2537     case 12: /* hex cohesive Lagrange cells */
2538       *numFaceVertices = 6; /* Face has 6 vertices */
2539       break;
2540     case 18: /* quadratic tet cohesive Lagrange cells */
2541       *numFaceVertices = 6; /* Face has 6 vertices */
2542       break;
2543     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2544       *numFaceVertices = 9; /* Face has 9 vertices */
2545       break;
2546     default:
2547       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2548     }
2549     break;
2550   default:
2551     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2552   }
2553   PetscFunctionReturn(0);
2554 }
2555 
2556 #undef __FUNCT__
2557 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2558 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2559 {
2560   const PetscInt maxFaceCases = 30;
2561   PetscInt       numFaceCases = 0;
2562   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2563   PetscInt      *off, *adj;
2564   PetscInt      *neighborCells, *tmpClosure;
2565   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2566   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2567   PetscErrorCode ierr;
2568 
2569   PetscFunctionBegin;
2570   /* For parallel partitioning, I think you have to communicate supports */
2571   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2572   cellDim = dim - cellHeight;
2573   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2574   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2575   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2576   if (cEnd - cStart == 0) {
2577     if (numVertices) *numVertices = 0;
2578     if (offsets)   *offsets   = NULL;
2579     if (adjacency) *adjacency = NULL;
2580     PetscFunctionReturn(0);
2581   }
2582   numCells  = cEnd - cStart;
2583   faceDepth = depth - cellHeight;
2584   /* Setup face recognition */
2585   if (faceDepth == 1) {
2586     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 */
2587 
2588     for (c = cStart; c < cEnd; ++c) {
2589       PetscInt corners;
2590 
2591       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2592       if (!cornersSeen[corners]) {
2593         PetscInt nFV;
2594 
2595         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2596         cornersSeen[corners] = 1;
2597 
2598         ierr = DMPlexGetNumFaceVertices_Internal(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2599 
2600         numFaceVertices[numFaceCases++] = nFV;
2601       }
2602     }
2603   }
2604   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2605   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2606   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2607   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2608   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2609   /* Count neighboring cells */
2610   for (cell = cStart; cell < cEnd; ++cell) {
2611     PetscInt numNeighbors = maxNeighbors, n;
2612 
2613     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2614     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2615     for (n = 0; n < numNeighbors; ++n) {
2616       PetscInt        cellPair[2];
2617       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2618       PetscInt        meetSize = 0;
2619       const PetscInt *meet    = NULL;
2620 
2621       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2622       if (cellPair[0] == cellPair[1]) continue;
2623       if (!found) {
2624         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2625         if (meetSize) {
2626           PetscInt f;
2627 
2628           for (f = 0; f < numFaceCases; ++f) {
2629             if (numFaceVertices[f] == meetSize) {
2630               found = PETSC_TRUE;
2631               break;
2632             }
2633           }
2634         }
2635         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2636       }
2637       if (found) ++off[cell-cStart+1];
2638     }
2639   }
2640   /* Prefix sum */
2641   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2642 
2643   if (adjacency) {
2644     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2645     /* Get neighboring cells */
2646     for (cell = cStart; cell < cEnd; ++cell) {
2647       PetscInt numNeighbors = maxNeighbors, n;
2648       PetscInt cellOffset   = 0;
2649 
2650       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2651       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2652       for (n = 0; n < numNeighbors; ++n) {
2653         PetscInt        cellPair[2];
2654         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2655         PetscInt        meetSize = 0;
2656         const PetscInt *meet    = NULL;
2657 
2658         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2659         if (cellPair[0] == cellPair[1]) continue;
2660         if (!found) {
2661           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2662           if (meetSize) {
2663             PetscInt f;
2664 
2665             for (f = 0; f < numFaceCases; ++f) {
2666               if (numFaceVertices[f] == meetSize) {
2667                 found = PETSC_TRUE;
2668                 break;
2669               }
2670             }
2671           }
2672           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2673         }
2674         if (found) {
2675           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2676           ++cellOffset;
2677         }
2678       }
2679     }
2680   }
2681   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2682   if (numVertices) *numVertices = numCells;
2683   if (offsets)   *offsets   = off;
2684   if (adjacency) *adjacency = adj;
2685   PetscFunctionReturn(0);
2686 }
2687 
2688 #if defined(PETSC_HAVE_CHACO)
2689 #if defined(PETSC_HAVE_UNISTD_H)
2690 #include <unistd.h>
2691 #endif
2692 /* Chaco does not have an include file */
2693 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2694                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2695                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2696                        int mesh_dims[3], double *goal, int global_method, int local_method,
2697                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2698 
2699 extern int FREE_GRAPH;
2700 
2701 #undef __FUNCT__
2702 #define __FUNCT__ "DMPlexPartition_Chaco"
2703 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2704 {
2705   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2706   MPI_Comm       comm;
2707   int            nvtxs          = numVertices; /* number of vertices in full graph */
2708   int           *vwgts          = NULL;   /* weights for all vertices */
2709   float         *ewgts          = NULL;   /* weights for all edges */
2710   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2711   char          *outassignname  = NULL;   /*  name of assignment output file */
2712   char          *outfilename    = NULL;   /* output file name */
2713   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2714   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2715   int            mesh_dims[3];            /* dimensions of mesh of processors */
2716   double        *goal          = NULL;    /* desired set sizes for each set */
2717   int            global_method = 1;       /* global partitioning algorithm */
2718   int            local_method  = 1;       /* local partitioning algorithm */
2719   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2720   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2721   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2722   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2723   long           seed          = 123636512; /* for random graph mutations */
2724   short int     *assignment;              /* Output partition */
2725   int            fd_stdout, fd_pipe[2];
2726   PetscInt      *points;
2727   PetscMPIInt    commSize;
2728   int            i, v, p;
2729   PetscErrorCode ierr;
2730 
2731   PetscFunctionBegin;
2732   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2733   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2734   if (!numVertices) {
2735     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2736     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2737     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2738     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2739     PetscFunctionReturn(0);
2740   }
2741   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2742   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2743 
2744   if (global_method == INERTIAL_METHOD) {
2745     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2746     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2747   }
2748   mesh_dims[0] = commSize;
2749   mesh_dims[1] = 1;
2750   mesh_dims[2] = 1;
2751   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2752   /* Chaco outputs to stdout. We redirect this to a buffer. */
2753   /* TODO: check error codes for UNIX calls */
2754 #if defined(PETSC_HAVE_UNISTD_H)
2755   {
2756     int piperet;
2757     piperet = pipe(fd_pipe);
2758     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2759     fd_stdout = dup(1);
2760     close(1);
2761     dup2(fd_pipe[1], 1);
2762   }
2763 #endif
2764   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2765                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2766                    vmax, ndims, eigtol, seed);
2767 #if defined(PETSC_HAVE_UNISTD_H)
2768   {
2769     char msgLog[10000];
2770     int  count;
2771 
2772     fflush(stdout);
2773     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2774     if (count < 0) count = 0;
2775     msgLog[count] = 0;
2776     close(1);
2777     dup2(fd_stdout, 1);
2778     close(fd_stdout);
2779     close(fd_pipe[0]);
2780     close(fd_pipe[1]);
2781     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2782   }
2783 #endif
2784   /* Convert to PetscSection+IS */
2785   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2786   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2787   for (v = 0; v < nvtxs; ++v) {
2788     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2789   }
2790   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2791   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2792   for (p = 0, i = 0; p < commSize; ++p) {
2793     for (v = 0; v < nvtxs; ++v) {
2794       if (assignment[v] == p) points[i++] = v;
2795     }
2796   }
2797   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2798   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2799   if (global_method == INERTIAL_METHOD) {
2800     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2801   }
2802   ierr = PetscFree(assignment);CHKERRQ(ierr);
2803   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2804   PetscFunctionReturn(0);
2805 }
2806 #endif
2807 
2808 #if defined(PETSC_HAVE_PARMETIS)
2809 #undef __FUNCT__
2810 #define __FUNCT__ "DMPlexPartition_ParMetis"
2811 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2812 {
2813   PetscFunctionBegin;
2814   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2815   PetscFunctionReturn(0);
2816 }
2817 #endif
2818 
2819 #undef __FUNCT__
2820 #define __FUNCT__ "DMPlexEnlargePartition"
2821 /* Expand the partition by BFS on the adjacency graph */
2822 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2823 {
2824   PetscHashI      h;
2825   const PetscInt *points;
2826   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2827   PetscInt        pStart, pEnd, part, q;
2828   PetscErrorCode  ierr;
2829 
2830   PetscFunctionBegin;
2831   PetscHashICreate(h);
2832   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2833   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2834   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2835   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2836   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2837   for (part = pStart; part < pEnd; ++part) {
2838     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2839 
2840     PetscHashIClear(h);
2841     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2842     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2843     /* Add all existing points to h */
2844     for (p = 0; p < numPoints; ++p) {
2845       const PetscInt point = points[off+p];
2846       PetscHashIAdd(h, point, 1);
2847     }
2848     PetscHashISize(h, nP);
2849     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2850     /* Add all points in next BFS level */
2851     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2852     for (p = 0; p < numPoints; ++p) {
2853       const PetscInt point = points[off+p];
2854       PetscInt       s     = start[point], e = start[point+1], a;
2855 
2856       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2857     }
2858     PetscHashISize(h, numNewPoints);
2859     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2860     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2861     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2862     totPoints += numNewPoints;
2863   }
2864   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2865   PetscHashIDestroy(h);
2866   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2867   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2868   for (part = pStart, q = 0; part < pEnd; ++part) {
2869     PetscInt numPoints, p;
2870 
2871     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2872     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2873     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2874   }
2875   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2876   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), 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 NULL
2896   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise 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(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2909 
2910   *origPartSection = NULL;
2911   *origPartition   = NULL;
2912   if (size == 1) {
2913     PetscInt *points;
2914     PetscInt  cStart, cEnd, c;
2915 
2916     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2917     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2918     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2919     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2920     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2921     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2922     for (c = cStart; c < cEnd; ++c) points[c] = c;
2923     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2924     PetscFunctionReturn(0);
2925   }
2926   if (height == 0) {
2927     PetscInt  numVertices;
2928     PetscInt *start     = NULL;
2929     PetscInt *adjacency = NULL;
2930 
2931     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2932     if (1) {
2933 #if defined(PETSC_HAVE_CHACO)
2934       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2935 #endif
2936     } else {
2937 #if defined(PETSC_HAVE_PARMETIS)
2938       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2939 #endif
2940     }
2941     if (enlarge) {
2942       *origPartSection = *partSection;
2943       *origPartition   = *partition;
2944 
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(PetscObjectComm((PetscObject)dm), 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 = 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(PetscObjectComm((PetscObject)dm), 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 = 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 
2998         partPoints = tmpPoints;
2999       }
3000       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3001       partSize += closureSize;
3002 
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 = 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) partPoints[partSize+c] = closure[c*2];
3026       partSize += closureSize;
3027 
3028       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3029       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3030     }
3031     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3032     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3033   }
3034   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3035   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3036   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3037   PetscFunctionReturn(0);
3038 }
3039 
3040 #undef __FUNCT__
3041 #define __FUNCT__ "DMPlexDistributeField"
3042 /*
3043   Input Parameters:
3044 . originalSection
3045 , originalVec
3046 
3047   Output Parameters:
3048 . newSection
3049 . newVec
3050 */
3051 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3052 {
3053   PetscSF        fieldSF;
3054   PetscInt      *remoteOffsets, fieldSize;
3055   PetscScalar   *originalValues, *newValues;
3056   PetscErrorCode ierr;
3057 
3058   PetscFunctionBegin;
3059   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3060 
3061   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3062   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3063   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3064 
3065   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3066   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3067   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3068   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3069   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3070   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3071   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3072   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3073   PetscFunctionReturn(0);
3074 }
3075 
3076 #undef __FUNCT__
3077 #define __FUNCT__ "DMPlexDistribute"
3078 /*@C
3079   DMPlexDistribute - Distributes the mesh and any associated sections.
3080 
3081   Not Collective
3082 
3083   Input Parameter:
3084 + dm  - The original DMPlex object
3085 . partitioner - The partitioning package, or NULL for the default
3086 - overlap - The overlap of partitions, 0 is the default
3087 
3088   Output Parameter:
3089 . parallelMesh - The distributed DMPlex object, or NULL
3090 
3091   Note: If the mesh was not distributed, the return value is NULL
3092 
3093   Level: intermediate
3094 
3095 .keywords: mesh, elements
3096 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3097 @*/
3098 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3099 {
3100   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3101   MPI_Comm               comm;
3102   const PetscInt         height = 0;
3103   PetscInt               dim, numRemoteRanks;
3104   IS                     origCellPart,        cellPart,        part;
3105   PetscSection           origCellPartSection, cellPartSection, partSection;
3106   PetscSFNode           *remoteRanks;
3107   PetscSF                partSF, pointSF, coneSF;
3108   ISLocalToGlobalMapping renumbering;
3109   PetscSection           originalConeSection, newConeSection;
3110   PetscInt              *remoteOffsets;
3111   PetscInt              *cones, *newCones, newConesSize;
3112   PetscBool              flg;
3113   PetscMPIInt            rank, numProcs, p;
3114   PetscErrorCode         ierr;
3115 
3116   PetscFunctionBegin;
3117   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3118   PetscValidPointer(dmParallel,4);
3119 
3120   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3121   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3122   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3123   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3124 
3125   *dmParallel = NULL;
3126   if (numProcs == 1) PetscFunctionReturn(0);
3127 
3128   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3129   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3130   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3131   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3132   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3133   if (!rank) numRemoteRanks = numProcs;
3134   else       numRemoteRanks = 0;
3135   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3136   for (p = 0; p < numRemoteRanks; ++p) {
3137     remoteRanks[p].rank  = p;
3138     remoteRanks[p].index = 0;
3139   }
3140   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3141   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3142   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3143   if (flg) {
3144     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3145     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3146     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3147     if (origCellPart) {
3148       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3149       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3150       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3151     }
3152     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3153   }
3154   /* Close the partition over the mesh */
3155   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3156   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3157   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3158   /* Create new mesh */
3159   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3160   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3161   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3162   pmesh = (DM_Plex*) (*dmParallel)->data;
3163   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3164   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3165   if (flg) {
3166     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3167     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3168     ierr = ISView(part, NULL);CHKERRQ(ierr);
3169     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3170     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3171     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3172   }
3173   /* Distribute cone section */
3174   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3175   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3176   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3177   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3178   {
3179     PetscInt pStart, pEnd, p;
3180 
3181     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3182     for (p = pStart; p < pEnd; ++p) {
3183       PetscInt coneSize;
3184       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3185       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3186     }
3187   }
3188   /* Communicate and renumber cones */
3189   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3190   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3191   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3192   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3193   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3194   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3195   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3196   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3197   if (flg) {
3198     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3199     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3200     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3201     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3202     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3203   }
3204   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3205   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3206   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3207   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3208   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3209   /* Create supports and stratify sieve */
3210   {
3211     PetscInt pStart, pEnd;
3212 
3213     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3214     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3215   }
3216   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3217   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3218   /* Distribute Coordinates */
3219   {
3220     PetscSection originalCoordSection, newCoordSection;
3221     Vec          originalCoordinates, newCoordinates;
3222     const char  *name;
3223 
3224     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3225     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3226     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3227     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3228     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3229     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3230 
3231     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3232     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3233     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3234   }
3235   /* Distribute labels */
3236   {
3237     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3238     PetscInt numLabels = 0, l;
3239 
3240     /* Bcast number of labels */
3241     while (next) {
3242       ++numLabels; next = next->next;
3243     }
3244     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3245     next = mesh->labels;
3246     for (l = 0; l < numLabels; ++l) {
3247       DMLabel         newLabel;
3248       const PetscInt *partArray;
3249       char           *name;
3250       PetscInt       *stratumSizes = NULL, *points = NULL;
3251       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3252       PetscInt        nameSize, s, p;
3253       PetscBool       isdepth;
3254       size_t          len = 0;
3255 
3256       /* Bcast name (could filter for no points) */
3257       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3258       nameSize = len;
3259       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3260       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3261       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3262       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3263       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3264       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3265       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3266       newLabel->name = name;
3267       /* Bcast numStrata (could filter for no points in stratum) */
3268       if (!rank) newLabel->numStrata = next->numStrata;
3269       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3270       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3271                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3272                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3273       /* Bcast stratumValues (could filter for no points in stratum) */
3274       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3275       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3276       /* Find size on each process and Scatter */
3277       if (!rank) {
3278         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3279         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3280         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3281         for (s = 0; s < next->numStrata; ++s) {
3282           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3283             const PetscInt point = next->points[p];
3284             PetscInt       proc;
3285 
3286             for (proc = 0; proc < numProcs; ++proc) {
3287               PetscInt dof, off, pPart;
3288 
3289               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3290               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3291               for (pPart = off; pPart < off+dof; ++pPart) {
3292                 if (partArray[pPart] == point) {
3293                   ++stratumSizes[proc*next->numStrata+s];
3294                   break;
3295                 }
3296               }
3297             }
3298           }
3299         }
3300         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3301       }
3302       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3303       /* Calculate stratumOffsets */
3304       newLabel->stratumOffsets[0] = 0;
3305       for (s = 0; s < newLabel->numStrata; ++s) {
3306         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3307       }
3308       /* Pack points and Scatter */
3309       if (!rank) {
3310         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3311         displs[0] = 0;
3312         for (p = 0; p < numProcs; ++p) {
3313           sendcnts[p] = 0;
3314           for (s = 0; s < next->numStrata; ++s) {
3315             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3316           }
3317           offsets[p]  = displs[p];
3318           displs[p+1] = displs[p] + sendcnts[p];
3319         }
3320         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3321         for (s = 0; s < next->numStrata; ++s) {
3322           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3323             const PetscInt point = next->points[p];
3324             PetscInt       proc;
3325 
3326             for (proc = 0; proc < numProcs; ++proc) {
3327               PetscInt dof, off, pPart;
3328 
3329               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3330               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3331               for (pPart = off; pPart < off+dof; ++pPart) {
3332                 if (partArray[pPart] == point) {
3333                   points[offsets[proc]++] = point;
3334                   break;
3335                 }
3336               }
3337             }
3338           }
3339         }
3340       }
3341       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3342       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3343       ierr = PetscFree(points);CHKERRQ(ierr);
3344       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3345       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3346       /* Renumber points */
3347       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3348       /* Sort points */
3349       for (s = 0; s < newLabel->numStrata; ++s) {
3350         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3351       }
3352       /* Insert into list */
3353       if (newNext) newNext->next = newLabel;
3354       else pmesh->labels = newLabel;
3355       newNext = newLabel;
3356       if (!rank) next = next->next;
3357     }
3358   }
3359   /* Cleanup Partition */
3360   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3361   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3362   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3363   ierr = ISDestroy(&part);CHKERRQ(ierr);
3364   /* Create point SF for parallel mesh */
3365   {
3366     const PetscInt *leaves;
3367     PetscSFNode    *remotePoints, *rowners, *lowners;
3368     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3369     PetscInt        pStart, pEnd;
3370 
3371     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3372     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3373     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3374     for (p=0; p<numRoots; p++) {
3375       rowners[p].rank  = -1;
3376       rowners[p].index = -1;
3377     }
3378     if (origCellPart) {
3379       /* Make sure cells in the original partition are not assigned to other procs */
3380       const PetscInt *origCells;
3381 
3382       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3383       for (p = 0; p < numProcs; ++p) {
3384         PetscInt dof, off, d;
3385 
3386         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3387         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3388         for (d = off; d < off+dof; ++d) {
3389           rowners[origCells[d]].rank = p;
3390         }
3391       }
3392       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3393     }
3394     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3395     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3396 
3397     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3398     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3399     for (p = 0; p < numLeaves; ++p) {
3400       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3401         lowners[p].rank  = rank;
3402         lowners[p].index = leaves ? leaves[p] : p;
3403       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3404         lowners[p].rank  = -2;
3405         lowners[p].index = -2;
3406       }
3407     }
3408     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3409       rowners[p].rank  = -3;
3410       rowners[p].index = -3;
3411     }
3412     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3413     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3414     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3415     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3416     for (p = 0; p < numLeaves; ++p) {
3417       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3418       if (lowners[p].rank != rank) ++numGhostPoints;
3419     }
3420     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3421     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3422     for (p = 0, gp = 0; p < numLeaves; ++p) {
3423       if (lowners[p].rank != rank) {
3424         ghostPoints[gp]        = leaves ? leaves[p] : p;
3425         remotePoints[gp].rank  = lowners[p].rank;
3426         remotePoints[gp].index = lowners[p].index;
3427         ++gp;
3428       }
3429     }
3430     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3431     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3432     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3433   }
3434   /* Cleanup */
3435   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3436   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3437   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3438   PetscFunctionReturn(0);
3439 }
3440 
3441 #if defined(PETSC_HAVE_TRIANGLE)
3442 #include <triangle.h>
3443 
3444 #undef __FUNCT__
3445 #define __FUNCT__ "InitInput_Triangle"
3446 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3447 {
3448   PetscFunctionBegin;
3449   inputCtx->numberofpoints             = 0;
3450   inputCtx->numberofpointattributes    = 0;
3451   inputCtx->pointlist                  = NULL;
3452   inputCtx->pointattributelist         = NULL;
3453   inputCtx->pointmarkerlist            = NULL;
3454   inputCtx->numberofsegments           = 0;
3455   inputCtx->segmentlist                = NULL;
3456   inputCtx->segmentmarkerlist          = NULL;
3457   inputCtx->numberoftriangleattributes = 0;
3458   inputCtx->trianglelist               = NULL;
3459   inputCtx->numberofholes              = 0;
3460   inputCtx->holelist                   = NULL;
3461   inputCtx->numberofregions            = 0;
3462   inputCtx->regionlist                 = NULL;
3463   PetscFunctionReturn(0);
3464 }
3465 
3466 #undef __FUNCT__
3467 #define __FUNCT__ "InitOutput_Triangle"
3468 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3469 {
3470   PetscFunctionBegin;
3471   outputCtx->numberofpoints        = 0;
3472   outputCtx->pointlist             = NULL;
3473   outputCtx->pointattributelist    = NULL;
3474   outputCtx->pointmarkerlist       = NULL;
3475   outputCtx->numberoftriangles     = 0;
3476   outputCtx->trianglelist          = NULL;
3477   outputCtx->triangleattributelist = NULL;
3478   outputCtx->neighborlist          = NULL;
3479   outputCtx->segmentlist           = NULL;
3480   outputCtx->segmentmarkerlist     = NULL;
3481   outputCtx->numberofedges         = 0;
3482   outputCtx->edgelist              = NULL;
3483   outputCtx->edgemarkerlist        = NULL;
3484   PetscFunctionReturn(0);
3485 }
3486 
3487 #undef __FUNCT__
3488 #define __FUNCT__ "FiniOutput_Triangle"
3489 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3490 {
3491   PetscFunctionBegin;
3492   free(outputCtx->pointmarkerlist);
3493   free(outputCtx->edgelist);
3494   free(outputCtx->edgemarkerlist);
3495   free(outputCtx->trianglelist);
3496   free(outputCtx->neighborlist);
3497   PetscFunctionReturn(0);
3498 }
3499 
3500 #undef __FUNCT__
3501 #define __FUNCT__ "DMPlexGenerate_Triangle"
3502 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3503 {
3504   MPI_Comm             comm;
3505   PetscInt             dim              = 2;
3506   const PetscBool      createConvexHull = PETSC_FALSE;
3507   const PetscBool      constrained      = PETSC_FALSE;
3508   struct triangulateio in;
3509   struct triangulateio out;
3510   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3511   PetscMPIInt          rank;
3512   PetscErrorCode       ierr;
3513 
3514   PetscFunctionBegin;
3515   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3516   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3517   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3518   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3519   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3520 
3521   in.numberofpoints = vEnd - vStart;
3522   if (in.numberofpoints > 0) {
3523     PetscSection coordSection;
3524     Vec          coordinates;
3525     PetscScalar *array;
3526 
3527     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3528     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3529     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3530     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3531     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3532     for (v = vStart; v < vEnd; ++v) {
3533       const PetscInt idx = v - vStart;
3534       PetscInt       off, d;
3535 
3536       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3537       for (d = 0; d < dim; ++d) {
3538         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3539       }
3540       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3541     }
3542     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3543   }
3544   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3545   in.numberofsegments = eEnd - eStart;
3546   if (in.numberofsegments > 0) {
3547     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
3548     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
3549     for (e = eStart; e < eEnd; ++e) {
3550       const PetscInt  idx = e - eStart;
3551       const PetscInt *cone;
3552 
3553       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3554 
3555       in.segmentlist[idx*2+0] = cone[0] - vStart;
3556       in.segmentlist[idx*2+1] = cone[1] - vStart;
3557 
3558       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3559     }
3560   }
3561 #if 0 /* Do not currently support holes */
3562   PetscReal *holeCoords;
3563   PetscInt   h, d;
3564 
3565   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3566   if (in.numberofholes > 0) {
3567     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3568     for (h = 0; h < in.numberofholes; ++h) {
3569       for (d = 0; d < dim; ++d) {
3570         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3571       }
3572     }
3573   }
3574 #endif
3575   if (!rank) {
3576     char args[32];
3577 
3578     /* Take away 'Q' for verbose output */
3579     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3580     if (createConvexHull) {
3581       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3582     }
3583     if (constrained) {
3584       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3585     }
3586     triangulate(args, &in, &out, NULL);
3587   }
3588   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3589   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3590   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3591   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3592   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3593 
3594   {
3595     const PetscInt numCorners  = 3;
3596     const PetscInt numCells    = out.numberoftriangles;
3597     const PetscInt numVertices = out.numberofpoints;
3598     const int     *cells      = out.trianglelist;
3599     const double  *meshCoords = out.pointlist;
3600 
3601     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3602     /* Set labels */
3603     for (v = 0; v < numVertices; ++v) {
3604       if (out.pointmarkerlist[v]) {
3605         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3606       }
3607     }
3608     if (interpolate) {
3609       for (e = 0; e < out.numberofedges; e++) {
3610         if (out.edgemarkerlist[e]) {
3611           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3612           const PetscInt *edges;
3613           PetscInt        numEdges;
3614 
3615           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3616           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3617           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3618           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3619         }
3620       }
3621     }
3622     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3623   }
3624 #if 0 /* Do not currently support holes */
3625   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3626 #endif
3627   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3628   PetscFunctionReturn(0);
3629 }
3630 
3631 #undef __FUNCT__
3632 #define __FUNCT__ "DMPlexRefine_Triangle"
3633 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3634 {
3635   MPI_Comm             comm;
3636   PetscInt             dim  = 2;
3637   struct triangulateio in;
3638   struct triangulateio out;
3639   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3640   PetscMPIInt          rank;
3641   PetscErrorCode       ierr;
3642 
3643   PetscFunctionBegin;
3644   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3645   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3646   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3647   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3648   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3649   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3650   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3651 
3652   in.numberofpoints = vEnd - vStart;
3653   if (in.numberofpoints > 0) {
3654     PetscSection coordSection;
3655     Vec          coordinates;
3656     PetscScalar *array;
3657 
3658     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3659     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3660     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3661     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3662     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3663     for (v = vStart; v < vEnd; ++v) {
3664       const PetscInt idx = v - vStart;
3665       PetscInt       off, d;
3666 
3667       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3668       for (d = 0; d < dim; ++d) {
3669         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3670       }
3671       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3672     }
3673     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3674   }
3675   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3676 
3677   in.numberofcorners   = 3;
3678   in.numberoftriangles = cEnd - cStart;
3679 
3680   in.trianglearealist  = (double*) maxVolumes;
3681   if (in.numberoftriangles > 0) {
3682     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
3683     for (c = cStart; c < cEnd; ++c) {
3684       const PetscInt idx      = c - cStart;
3685       PetscInt      *closure = NULL;
3686       PetscInt       closureSize;
3687 
3688       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3689       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3690       for (v = 0; v < 3; ++v) {
3691         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3692       }
3693       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3694     }
3695   }
3696   /* TODO: Segment markers are missing on input */
3697 #if 0 /* Do not currently support holes */
3698   PetscReal *holeCoords;
3699   PetscInt   h, d;
3700 
3701   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3702   if (in.numberofholes > 0) {
3703     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3704     for (h = 0; h < in.numberofholes; ++h) {
3705       for (d = 0; d < dim; ++d) {
3706         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3707       }
3708     }
3709   }
3710 #endif
3711   if (!rank) {
3712     char args[32];
3713 
3714     /* Take away 'Q' for verbose output */
3715     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3716     triangulate(args, &in, &out, NULL);
3717   }
3718   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3719   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3720   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3721   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3722   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3723 
3724   {
3725     const PetscInt numCorners  = 3;
3726     const PetscInt numCells    = out.numberoftriangles;
3727     const PetscInt numVertices = out.numberofpoints;
3728     const int     *cells      = out.trianglelist;
3729     const double  *meshCoords = out.pointlist;
3730     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3731 
3732     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3733     /* Set labels */
3734     for (v = 0; v < numVertices; ++v) {
3735       if (out.pointmarkerlist[v]) {
3736         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3737       }
3738     }
3739     if (interpolate) {
3740       PetscInt e;
3741 
3742       for (e = 0; e < out.numberofedges; e++) {
3743         if (out.edgemarkerlist[e]) {
3744           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3745           const PetscInt *edges;
3746           PetscInt        numEdges;
3747 
3748           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3749           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3750           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3751           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3752         }
3753       }
3754     }
3755     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3756   }
3757 #if 0 /* Do not currently support holes */
3758   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3759 #endif
3760   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3761   PetscFunctionReturn(0);
3762 }
3763 #endif
3764 
3765 #if defined(PETSC_HAVE_TETGEN)
3766 #include <tetgen.h>
3767 #undef __FUNCT__
3768 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3769 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3770 {
3771   MPI_Comm       comm;
3772   const PetscInt dim  = 3;
3773   ::tetgenio     in;
3774   ::tetgenio     out;
3775   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3776   PetscMPIInt    rank;
3777   PetscErrorCode ierr;
3778 
3779   PetscFunctionBegin;
3780   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3781   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3782   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3783   in.numberofpoints = vEnd - vStart;
3784   if (in.numberofpoints > 0) {
3785     PetscSection coordSection;
3786     Vec          coordinates;
3787     PetscScalar *array;
3788 
3789     in.pointlist       = new double[in.numberofpoints*dim];
3790     in.pointmarkerlist = new int[in.numberofpoints];
3791 
3792     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3793     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3794     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3795     for (v = vStart; v < vEnd; ++v) {
3796       const PetscInt idx = v - vStart;
3797       PetscInt       off, d;
3798 
3799       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3800       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3801       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3802     }
3803     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3804   }
3805   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3806 
3807   in.numberoffacets = fEnd - fStart;
3808   if (in.numberoffacets > 0) {
3809     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3810     in.facetmarkerlist = new int[in.numberoffacets];
3811     for (f = fStart; f < fEnd; ++f) {
3812       const PetscInt idx     = f - fStart;
3813       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3814 
3815       in.facetlist[idx].numberofpolygons = 1;
3816       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3817       in.facetlist[idx].numberofholes    = 0;
3818       in.facetlist[idx].holelist         = NULL;
3819 
3820       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3821       for (p = 0; p < numPoints*2; p += 2) {
3822         const PetscInt point = points[p];
3823         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3824       }
3825 
3826       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3827       poly->numberofvertices = numVertices;
3828       poly->vertexlist       = new int[poly->numberofvertices];
3829       for (v = 0; v < numVertices; ++v) {
3830         const PetscInt vIdx = points[v] - vStart;
3831         poly->vertexlist[v] = vIdx;
3832       }
3833       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3834       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3835     }
3836   }
3837   if (!rank) {
3838     char args[32];
3839 
3840     /* Take away 'Q' for verbose output */
3841     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3842     ::tetrahedralize(args, &in, &out);
3843   }
3844   {
3845     const PetscInt numCorners  = 4;
3846     const PetscInt numCells    = out.numberoftetrahedra;
3847     const PetscInt numVertices = out.numberofpoints;
3848     const int     *cells      = out.tetrahedronlist;
3849     const double  *meshCoords = out.pointlist;
3850 
3851     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3852     /* Set labels */
3853     for (v = 0; v < numVertices; ++v) {
3854       if (out.pointmarkerlist[v]) {
3855         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3856       }
3857     }
3858     if (interpolate) {
3859       PetscInt e;
3860 
3861       for (e = 0; e < out.numberofedges; e++) {
3862         if (out.edgemarkerlist[e]) {
3863           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3864           const PetscInt *edges;
3865           PetscInt        numEdges;
3866 
3867           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3868           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3869           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3870           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3871         }
3872       }
3873       for (f = 0; f < out.numberoftrifaces; f++) {
3874         if (out.trifacemarkerlist[f]) {
3875           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3876           const PetscInt *faces;
3877           PetscInt        numFaces;
3878 
3879           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3880           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3881           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3882           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3883         }
3884       }
3885     }
3886     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3887   }
3888   PetscFunctionReturn(0);
3889 }
3890 
3891 #undef __FUNCT__
3892 #define __FUNCT__ "DMPlexRefine_Tetgen"
3893 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3894 {
3895   MPI_Comm       comm;
3896   const PetscInt dim  = 3;
3897   ::tetgenio     in;
3898   ::tetgenio     out;
3899   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3900   PetscMPIInt    rank;
3901   PetscErrorCode ierr;
3902 
3903   PetscFunctionBegin;
3904   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3905   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3906   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3907   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3908   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3909 
3910   in.numberofpoints = vEnd - vStart;
3911   if (in.numberofpoints > 0) {
3912     PetscSection coordSection;
3913     Vec          coordinates;
3914     PetscScalar *array;
3915 
3916     in.pointlist       = new double[in.numberofpoints*dim];
3917     in.pointmarkerlist = new int[in.numberofpoints];
3918 
3919     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3920     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3921     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3922     for (v = vStart; v < vEnd; ++v) {
3923       const PetscInt idx = v - vStart;
3924       PetscInt       off, d;
3925 
3926       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3927       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3928       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3929     }
3930     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3931   }
3932   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3933 
3934   in.numberofcorners       = 4;
3935   in.numberoftetrahedra    = cEnd - cStart;
3936   in.tetrahedronvolumelist = (double*) maxVolumes;
3937   if (in.numberoftetrahedra > 0) {
3938     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3939     for (c = cStart; c < cEnd; ++c) {
3940       const PetscInt idx      = c - cStart;
3941       PetscInt      *closure = NULL;
3942       PetscInt       closureSize;
3943 
3944       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3945       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3946       for (v = 0; v < 4; ++v) {
3947         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3948       }
3949       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3950     }
3951   }
3952   /* TODO: Put in boundary faces with markers */
3953   if (!rank) {
3954     char args[32];
3955 
3956     /* Take away 'Q' for verbose output */
3957     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3958     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3959     ::tetrahedralize(args, &in, &out);
3960   }
3961   in.tetrahedronvolumelist = NULL;
3962 
3963   {
3964     const PetscInt numCorners  = 4;
3965     const PetscInt numCells    = out.numberoftetrahedra;
3966     const PetscInt numVertices = out.numberofpoints;
3967     const int     *cells      = out.tetrahedronlist;
3968     const double  *meshCoords = out.pointlist;
3969     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3970 
3971     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3972     /* Set labels */
3973     for (v = 0; v < numVertices; ++v) {
3974       if (out.pointmarkerlist[v]) {
3975         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3976       }
3977     }
3978     if (interpolate) {
3979       PetscInt e, f;
3980 
3981       for (e = 0; e < out.numberofedges; e++) {
3982         if (out.edgemarkerlist[e]) {
3983           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3984           const PetscInt *edges;
3985           PetscInt        numEdges;
3986 
3987           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3988           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3989           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3990           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3991         }
3992       }
3993       for (f = 0; f < out.numberoftrifaces; f++) {
3994         if (out.trifacemarkerlist[f]) {
3995           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3996           const PetscInt *faces;
3997           PetscInt        numFaces;
3998 
3999           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4000           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4001           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4002           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4003         }
4004       }
4005     }
4006     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4007   }
4008   PetscFunctionReturn(0);
4009 }
4010 #endif
4011 
4012 #if defined(PETSC_HAVE_CTETGEN)
4013 #include "ctetgen.h"
4014 
4015 #undef __FUNCT__
4016 #define __FUNCT__ "DMPlexGenerate_CTetgen"
4017 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4018 {
4019   MPI_Comm       comm;
4020   const PetscInt dim  = 3;
4021   PLC           *in, *out;
4022   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4023   PetscMPIInt    rank;
4024   PetscErrorCode ierr;
4025 
4026   PetscFunctionBegin;
4027   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4028   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
4029   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4030   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4031   ierr = PLCCreate(&in);CHKERRQ(ierr);
4032   ierr = PLCCreate(&out);CHKERRQ(ierr);
4033 
4034   in->numberofpoints = vEnd - vStart;
4035   if (in->numberofpoints > 0) {
4036     PetscSection coordSection;
4037     Vec          coordinates;
4038     PetscScalar *array;
4039 
4040     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4041     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4042     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4043     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4044     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4045     for (v = vStart; v < vEnd; ++v) {
4046       const PetscInt idx = v - vStart;
4047       PetscInt       off, d, m;
4048 
4049       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4050       for (d = 0; d < dim; ++d) {
4051         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4052       }
4053       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
4054 
4055       in->pointmarkerlist[idx] = (int) m;
4056     }
4057     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4058   }
4059   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4060 
4061   in->numberoffacets = fEnd - fStart;
4062   if (in->numberoffacets > 0) {
4063     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
4064     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
4065     for (f = fStart; f < fEnd; ++f) {
4066       const PetscInt idx     = f - fStart;
4067       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
4068       polygon       *poly;
4069 
4070       in->facetlist[idx].numberofpolygons = 1;
4071 
4072       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
4073 
4074       in->facetlist[idx].numberofholes    = 0;
4075       in->facetlist[idx].holelist         = NULL;
4076 
4077       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4078       for (p = 0; p < numPoints*2; p += 2) {
4079         const PetscInt point = points[p];
4080         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4081       }
4082 
4083       poly                   = in->facetlist[idx].polygonlist;
4084       poly->numberofvertices = numVertices;
4085       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
4086       for (v = 0; v < numVertices; ++v) {
4087         const PetscInt vIdx = points[v] - vStart;
4088         poly->vertexlist[v] = vIdx;
4089       }
4090       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
4091       in->facetmarkerlist[idx] = (int) m;
4092       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4093     }
4094   }
4095   if (!rank) {
4096     TetGenOpts t;
4097 
4098     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4099     t.in        = boundary; /* Should go away */
4100     t.plc       = 1;
4101     t.quality   = 1;
4102     t.edgesout  = 1;
4103     t.zeroindex = 1;
4104     t.quiet     = 1;
4105     t.verbose   = verbose;
4106     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
4107     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4108   }
4109   {
4110     const PetscInt numCorners  = 4;
4111     const PetscInt numCells    = out->numberoftetrahedra;
4112     const PetscInt numVertices = out->numberofpoints;
4113     const int     *cells      = out->tetrahedronlist;
4114     const double  *meshCoords = out->pointlist;
4115 
4116     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4117     /* Set labels */
4118     for (v = 0; v < numVertices; ++v) {
4119       if (out->pointmarkerlist[v]) {
4120         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
4121       }
4122     }
4123     if (interpolate) {
4124       PetscInt e;
4125 
4126       for (e = 0; e < out->numberofedges; e++) {
4127         if (out->edgemarkerlist[e]) {
4128           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4129           const PetscInt *edges;
4130           PetscInt        numEdges;
4131 
4132           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4133           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4134           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
4135           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4136         }
4137       }
4138       for (f = 0; f < out->numberoftrifaces; f++) {
4139         if (out->trifacemarkerlist[f]) {
4140           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4141           const PetscInt *faces;
4142           PetscInt        numFaces;
4143 
4144           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4145           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4146           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
4147           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4148         }
4149       }
4150     }
4151     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4152   }
4153 
4154   ierr = PLCDestroy(&in);CHKERRQ(ierr);
4155   ierr = PLCDestroy(&out);CHKERRQ(ierr);
4156   PetscFunctionReturn(0);
4157 }
4158 
4159 #undef __FUNCT__
4160 #define __FUNCT__ "DMPlexRefine_CTetgen"
4161 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
4162 {
4163   MPI_Comm       comm;
4164   const PetscInt dim  = 3;
4165   PLC           *in, *out;
4166   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4167   PetscMPIInt    rank;
4168   PetscErrorCode ierr;
4169 
4170   PetscFunctionBegin;
4171   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4172   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
4173   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4174   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4175   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4176   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4177   ierr = PLCCreate(&in);CHKERRQ(ierr);
4178   ierr = PLCCreate(&out);CHKERRQ(ierr);
4179 
4180   in->numberofpoints = vEnd - vStart;
4181   if (in->numberofpoints > 0) {
4182     PetscSection coordSection;
4183     Vec          coordinates;
4184     PetscScalar *array;
4185 
4186     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4187     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4188     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4189     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4190     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4191     for (v = vStart; v < vEnd; ++v) {
4192       const PetscInt idx = v - vStart;
4193       PetscInt       off, d, m;
4194 
4195       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4196       for (d = 0; d < dim; ++d) {
4197         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4198       }
4199       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
4200 
4201       in->pointmarkerlist[idx] = (int) m;
4202     }
4203     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4204   }
4205   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4206 
4207   in->numberofcorners       = 4;
4208   in->numberoftetrahedra    = cEnd - cStart;
4209   in->tetrahedronvolumelist = maxVolumes;
4210   if (in->numberoftetrahedra > 0) {
4211     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
4212     for (c = cStart; c < cEnd; ++c) {
4213       const PetscInt idx      = c - cStart;
4214       PetscInt      *closure = NULL;
4215       PetscInt       closureSize;
4216 
4217       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4218       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4219       for (v = 0; v < 4; ++v) {
4220         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4221       }
4222       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4223     }
4224   }
4225   if (!rank) {
4226     TetGenOpts t;
4227 
4228     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4229 
4230     t.in        = dm; /* Should go away */
4231     t.refine    = 1;
4232     t.varvolume = 1;
4233     t.quality   = 1;
4234     t.edgesout  = 1;
4235     t.zeroindex = 1;
4236     t.quiet     = 1;
4237     t.verbose   = verbose; /* Change this */
4238 
4239     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
4240     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4241   }
4242   {
4243     const PetscInt numCorners  = 4;
4244     const PetscInt numCells    = out->numberoftetrahedra;
4245     const PetscInt numVertices = out->numberofpoints;
4246     const int     *cells       = out->tetrahedronlist;
4247     const double  *meshCoords  = out->pointlist;
4248     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4249 
4250     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4251     /* Set labels */
4252     for (v = 0; v < numVertices; ++v) {
4253       if (out->pointmarkerlist[v]) {
4254         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
4255       }
4256     }
4257     if (interpolate) {
4258       PetscInt e, f;
4259 
4260       for (e = 0; e < out->numberofedges; e++) {
4261         if (out->edgemarkerlist[e]) {
4262           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4263           const PetscInt *edges;
4264           PetscInt        numEdges;
4265 
4266           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4267           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4268           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
4269           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4270         }
4271       }
4272       for (f = 0; f < out->numberoftrifaces; f++) {
4273         if (out->trifacemarkerlist[f]) {
4274           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4275           const PetscInt *faces;
4276           PetscInt        numFaces;
4277 
4278           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4279           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4280           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
4281           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4282         }
4283       }
4284     }
4285     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4286   }
4287   ierr = PLCDestroy(&in);CHKERRQ(ierr);
4288   ierr = PLCDestroy(&out);CHKERRQ(ierr);
4289   PetscFunctionReturn(0);
4290 }
4291 #endif
4292 
4293 #undef __FUNCT__
4294 #define __FUNCT__ "DMPlexGenerate"
4295 /*@C
4296   DMPlexGenerate - Generates a mesh.
4297 
4298   Not Collective
4299 
4300   Input Parameters:
4301 + boundary - The DMPlex boundary object
4302 . name - The mesh generation package name
4303 - interpolate - Flag to create intermediate mesh elements
4304 
4305   Output Parameter:
4306 . mesh - The DMPlex object
4307 
4308   Level: intermediate
4309 
4310 .keywords: mesh, elements
4311 .seealso: DMPlexCreate(), DMRefine()
4312 @*/
4313 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
4314 {
4315   PetscInt       dim;
4316   char           genname[1024];
4317   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4318   PetscErrorCode ierr;
4319 
4320   PetscFunctionBegin;
4321   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
4322   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
4323   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
4324   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
4325   if (flg) name = genname;
4326   if (name) {
4327     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
4328     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
4329     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
4330   }
4331   switch (dim) {
4332   case 1:
4333     if (!name || isTriangle) {
4334 #if defined(PETSC_HAVE_TRIANGLE)
4335       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
4336 #else
4337       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4338 #endif
4339     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4340     break;
4341   case 2:
4342     if (!name || isCTetgen) {
4343 #if defined(PETSC_HAVE_CTETGEN)
4344       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4345 #else
4346       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4347 #endif
4348     } else if (isTetgen) {
4349 #if defined(PETSC_HAVE_TETGEN)
4350       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4351 #else
4352       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4353 #endif
4354     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4355     break;
4356   default:
4357     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4358   }
4359   PetscFunctionReturn(0);
4360 }
4361 
4362 typedef PetscInt CellRefiner;
4363 
4364 #undef __FUNCT__
4365 #define __FUNCT__ "GetDepthStart_Private"
4366 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
4367 {
4368   PetscFunctionBegin;
4369   if (cStart) *cStart = 0;
4370   if (vStart) *vStart = depthSize[depth];
4371   if (fStart) *fStart = depthSize[depth] + depthSize[0];
4372   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4373   PetscFunctionReturn(0);
4374 }
4375 
4376 #undef __FUNCT__
4377 #define __FUNCT__ "GetDepthEnd_Private"
4378 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
4379 {
4380   PetscFunctionBegin;
4381   if (cEnd) *cEnd = depthSize[depth];
4382   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
4383   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4384   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
4385   PetscFunctionReturn(0);
4386 }
4387 
4388 #undef __FUNCT__
4389 #define __FUNCT__ "CellRefinerGetSizes"
4390 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
4391 {
4392   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
4393   PetscErrorCode ierr;
4394 
4395   PetscFunctionBegin;
4396   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4397   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4398   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4399   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4400   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4401   switch (refiner) {
4402   case 1:
4403     /* Simplicial 2D */
4404     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
4405     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
4406     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
4407     break;
4408   case 3:
4409     /* Hybrid 2D */
4410     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4411     cMax = PetscMin(cEnd, cMax);
4412     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4413     fMax         = PetscMin(fEnd, fMax);
4414     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
4415     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 */
4416     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
4417     break;
4418   case 2:
4419     /* Hex 2D */
4420     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
4421     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
4422     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
4423     break;
4424   default:
4425     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4426   }
4427   PetscFunctionReturn(0);
4428 }
4429 
4430 #undef __FUNCT__
4431 #define __FUNCT__ "CellRefinerSetConeSizes"
4432 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4433 {
4434   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
4435   PetscErrorCode ierr;
4436 
4437   PetscFunctionBegin;
4438   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4439   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4440   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4441   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4442   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4443   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4444   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4445   switch (refiner) {
4446   case 1:
4447     /* Simplicial 2D */
4448     /* All cells have 3 faces */
4449     for (c = cStart; c < cEnd; ++c) {
4450       for (r = 0; r < 4; ++r) {
4451         const PetscInt newp = (c - cStart)*4 + r;
4452 
4453         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4454       }
4455     }
4456     /* Split faces have 2 vertices and the same cells as the parent */
4457     for (f = fStart; f < fEnd; ++f) {
4458       for (r = 0; r < 2; ++r) {
4459         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4460         PetscInt       size;
4461 
4462         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4463         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4464         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4465       }
4466     }
4467     /* Interior faces have 2 vertices and 2 cells */
4468     for (c = cStart; c < cEnd; ++c) {
4469       for (r = 0; r < 3; ++r) {
4470         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4471 
4472         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4473         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4474       }
4475     }
4476     /* Old vertices have identical supports */
4477     for (v = vStart; v < vEnd; ++v) {
4478       const PetscInt newp = vStartNew + (v - vStart);
4479       PetscInt       size;
4480 
4481       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4482       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4483     }
4484     /* Face vertices have 2 + cells*2 supports */
4485     for (f = fStart; f < fEnd; ++f) {
4486       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4487       PetscInt       size;
4488 
4489       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4490       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
4491     }
4492     break;
4493   case 2:
4494     /* Hex 2D */
4495     /* All cells have 4 faces */
4496     for (c = cStart; c < cEnd; ++c) {
4497       for (r = 0; r < 4; ++r) {
4498         const PetscInt newp = (c - cStart)*4 + r;
4499 
4500         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4501       }
4502     }
4503     /* Split faces have 2 vertices and the same cells as the parent */
4504     for (f = fStart; f < fEnd; ++f) {
4505       for (r = 0; r < 2; ++r) {
4506         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4507         PetscInt       size;
4508 
4509         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4510         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4511         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4512       }
4513     }
4514     /* Interior faces have 2 vertices and 2 cells */
4515     for (c = cStart; c < cEnd; ++c) {
4516       for (r = 0; r < 4; ++r) {
4517         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4518 
4519         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4520         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4521       }
4522     }
4523     /* Old vertices have identical supports */
4524     for (v = vStart; v < vEnd; ++v) {
4525       const PetscInt newp = vStartNew + (v - vStart);
4526       PetscInt       size;
4527 
4528       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4529       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4530     }
4531     /* Face vertices have 2 + cells supports */
4532     for (f = fStart; f < fEnd; ++f) {
4533       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4534       PetscInt       size;
4535 
4536       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4537       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
4538     }
4539     /* Cell vertices have 4 supports */
4540     for (c = cStart; c < cEnd; ++c) {
4541       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4542 
4543       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
4544     }
4545     break;
4546   case 3:
4547     /* Hybrid 2D */
4548     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4549     cMax = PetscMin(cEnd, cMax);
4550     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4551     fMax = PetscMin(fEnd, fMax);
4552     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4553     /* Interior cells have 3 faces */
4554     for (c = cStart; c < cMax; ++c) {
4555       for (r = 0; r < 4; ++r) {
4556         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
4557 
4558         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4559       }
4560     }
4561     /* Hybrid cells have 4 faces */
4562     for (c = cMax; c < cEnd; ++c) {
4563       for (r = 0; r < 2; ++r) {
4564         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
4565 
4566         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4567       }
4568     }
4569     /* Interior split faces have 2 vertices and the same cells as the parent */
4570     for (f = fStart; f < fMax; ++f) {
4571       for (r = 0; r < 2; ++r) {
4572         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4573         PetscInt       size;
4574 
4575         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4576         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4577         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4578       }
4579     }
4580     /* Interior cell faces have 2 vertices and 2 cells */
4581     for (c = cStart; c < cMax; ++c) {
4582       for (r = 0; r < 3; ++r) {
4583         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4584 
4585         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4586         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4587       }
4588     }
4589     /* Hybrid faces have 2 vertices and the same cells */
4590     for (f = fMax; f < fEnd; ++f) {
4591       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4592       PetscInt       size;
4593 
4594       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4595       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4596       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4597     }
4598     /* Hybrid cell faces have 2 vertices and 2 cells */
4599     for (c = cMax; c < cEnd; ++c) {
4600       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4601 
4602       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4603       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4604     }
4605     /* Old vertices have identical supports */
4606     for (v = vStart; v < vEnd; ++v) {
4607       const PetscInt newp = vStartNew + (v - vStart);
4608       PetscInt       size;
4609 
4610       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4611       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4612     }
4613     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4614     for (f = fStart; f < fMax; ++f) {
4615       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4616       const PetscInt *support;
4617       PetscInt       size, newSize = 2, s;
4618 
4619       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4620       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4621       for (s = 0; s < size; ++s) {
4622         if (support[s] >= cMax) newSize += 1;
4623         else newSize += 2;
4624       }
4625       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
4626     }
4627     break;
4628   default:
4629     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4630   }
4631   PetscFunctionReturn(0);
4632 }
4633 
4634 #undef __FUNCT__
4635 #define __FUNCT__ "CellRefinerSetCones"
4636 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4637 {
4638   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;
4639   PetscInt       maxSupportSize, *supportRef;
4640   PetscErrorCode ierr;
4641 
4642   PetscFunctionBegin;
4643   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4644   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4645   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4646   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4647   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4648   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4649   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4650   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
4651   switch (refiner) {
4652   case 1:
4653     /* Simplicial 2D */
4654     /*
4655      2
4656      |\
4657      | \
4658      |  \
4659      |   \
4660      | C  \
4661      |     \
4662      |      \
4663      2---1---1
4664      |\  D  / \
4665      | 2   0   \
4666      |A \ /  B  \
4667      0---0-------1
4668      */
4669     /* All cells have 3 faces */
4670     for (c = cStart; c < cEnd; ++c) {
4671       const PetscInt  newp = cStartNew + (c - cStart)*4;
4672       const PetscInt *cone, *ornt;
4673       PetscInt        coneNew[3], orntNew[3];
4674 
4675       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4676       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4677       /* A triangle */
4678       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4679       orntNew[0] = ornt[0];
4680       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4681       orntNew[1] = -2;
4682       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4683       orntNew[2] = ornt[2];
4684       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4685       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4686 #if 1
4687       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4688       for (p = 0; p < 3; ++p) {
4689         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4690       }
4691 #endif
4692       /* B triangle */
4693       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4694       orntNew[0] = ornt[0];
4695       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4696       orntNew[1] = ornt[1];
4697       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4698       orntNew[2] = -2;
4699       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4700       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4701 #if 1
4702       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4703       for (p = 0; p < 3; ++p) {
4704         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4705       }
4706 #endif
4707       /* C triangle */
4708       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4709       orntNew[0] = -2;
4710       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4711       orntNew[1] = ornt[1];
4712       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4713       orntNew[2] = ornt[2];
4714       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4715       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4716 #if 1
4717       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4718       for (p = 0; p < 3; ++p) {
4719         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4720       }
4721 #endif
4722       /* D triangle */
4723       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4724       orntNew[0] = 0;
4725       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4726       orntNew[1] = 0;
4727       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4728       orntNew[2] = 0;
4729       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4730       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4731 #if 1
4732       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4733       for (p = 0; p < 3; ++p) {
4734         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4735       }
4736 #endif
4737     }
4738     /* Split faces have 2 vertices and the same cells as the parent */
4739     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4740     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4741     for (f = fStart; f < fEnd; ++f) {
4742       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4743 
4744       for (r = 0; r < 2; ++r) {
4745         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4746         const PetscInt *cone, *support;
4747         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4748 
4749         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4750         coneNew[0]       = vStartNew + (cone[0] - vStart);
4751         coneNew[1]       = vStartNew + (cone[1] - vStart);
4752         coneNew[(r+1)%2] = newv;
4753         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4754 #if 1
4755         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4756         for (p = 0; p < 2; ++p) {
4757           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4758         }
4759 #endif
4760         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4761         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4762         for (s = 0; s < supportSize; ++s) {
4763           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4764           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4765           for (c = 0; c < coneSize; ++c) {
4766             if (cone[c] == f) break;
4767           }
4768           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4769         }
4770         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4771 #if 1
4772         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4773         for (p = 0; p < supportSize; ++p) {
4774           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4775         }
4776 #endif
4777       }
4778     }
4779     /* Interior faces have 2 vertices and 2 cells */
4780     for (c = cStart; c < cEnd; ++c) {
4781       const PetscInt *cone;
4782 
4783       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4784       for (r = 0; r < 3; ++r) {
4785         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4786         PetscInt       coneNew[2];
4787         PetscInt       supportNew[2];
4788 
4789         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4790         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4791         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4792 #if 1
4793         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4794         for (p = 0; p < 2; ++p) {
4795           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4796         }
4797 #endif
4798         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4799         supportNew[1] = (c - cStart)*4 + 3;
4800         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4801 #if 1
4802         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4803         for (p = 0; p < 2; ++p) {
4804           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4805         }
4806 #endif
4807       }
4808     }
4809     /* Old vertices have identical supports */
4810     for (v = vStart; v < vEnd; ++v) {
4811       const PetscInt  newp = vStartNew + (v - vStart);
4812       const PetscInt *support, *cone;
4813       PetscInt        size, s;
4814 
4815       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4816       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4817       for (s = 0; s < size; ++s) {
4818         PetscInt r = 0;
4819 
4820         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4821         if (cone[1] == v) r = 1;
4822         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4823       }
4824       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4825 #if 1
4826       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4827       for (p = 0; p < size; ++p) {
4828         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4829       }
4830 #endif
4831     }
4832     /* Face vertices have 2 + cells*2 supports */
4833     for (f = fStart; f < fEnd; ++f) {
4834       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4835       const PetscInt *cone, *support;
4836       PetscInt        size, s;
4837 
4838       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4839       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4840       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4841       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4842       for (s = 0; s < size; ++s) {
4843         PetscInt r = 0;
4844 
4845         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4846         if      (cone[1] == f) r = 1;
4847         else if (cone[2] == f) r = 2;
4848         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4849         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
4850       }
4851       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4852 #if 1
4853       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4854       for (p = 0; p < 2+size*2; ++p) {
4855         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4856       }
4857 #endif
4858     }
4859     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4860     break;
4861   case 2:
4862     /* Hex 2D */
4863     /*
4864      3---------2---------2
4865      |         |         |
4866      |    D    2    C    |
4867      |         |         |
4868      3----3----0----1----1
4869      |         |         |
4870      |    A    0    B    |
4871      |         |         |
4872      0---------0---------1
4873      */
4874     /* All cells have 4 faces */
4875     for (c = cStart; c < cEnd; ++c) {
4876       const PetscInt  newp = (c - cStart)*4;
4877       const PetscInt *cone, *ornt;
4878       PetscInt        coneNew[4], orntNew[4];
4879 
4880       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4881       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4882       /* A quad */
4883       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4884       orntNew[0] = ornt[0];
4885       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4886       orntNew[1] = 0;
4887       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4888       orntNew[2] = -2;
4889       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
4890       orntNew[3] = ornt[3];
4891       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4892       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4893 #if 1
4894       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4895       for (p = 0; p < 4; ++p) {
4896         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4897       }
4898 #endif
4899       /* B quad */
4900       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4901       orntNew[0] = ornt[0];
4902       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4903       orntNew[1] = ornt[1];
4904       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4905       orntNew[2] = 0;
4906       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4907       orntNew[3] = -2;
4908       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4909       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4910 #if 1
4911       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4912       for (p = 0; p < 4; ++p) {
4913         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4914       }
4915 #endif
4916       /* C quad */
4917       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4918       orntNew[0] = -2;
4919       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4920       orntNew[1] = ornt[1];
4921       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4922       orntNew[2] = ornt[2];
4923       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4924       orntNew[3] = 0;
4925       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4926       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4927 #if 1
4928       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4929       for (p = 0; p < 4; ++p) {
4930         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4931       }
4932 #endif
4933       /* D quad */
4934       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4935       orntNew[0] = 0;
4936       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4937       orntNew[1] = -2;
4938       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4939       orntNew[2] = ornt[2];
4940       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
4941       orntNew[3] = ornt[3];
4942       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4943       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4944 #if 1
4945       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4946       for (p = 0; p < 4; ++p) {
4947         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4948       }
4949 #endif
4950     }
4951     /* Split faces have 2 vertices and the same cells as the parent */
4952     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4953     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4954     for (f = fStart; f < fEnd; ++f) {
4955       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4956 
4957       for (r = 0; r < 2; ++r) {
4958         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4959         const PetscInt *cone, *support;
4960         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4961 
4962         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4963         coneNew[0]       = vStartNew + (cone[0] - vStart);
4964         coneNew[1]       = vStartNew + (cone[1] - vStart);
4965         coneNew[(r+1)%2] = newv;
4966         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4967 #if 1
4968         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4969         for (p = 0; p < 2; ++p) {
4970           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4971         }
4972 #endif
4973         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4974         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4975         for (s = 0; s < supportSize; ++s) {
4976           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4977           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4978           for (c = 0; c < coneSize; ++c) {
4979             if (cone[c] == f) break;
4980           }
4981           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
4982         }
4983         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4984 #if 1
4985         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4986         for (p = 0; p < supportSize; ++p) {
4987           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4988         }
4989 #endif
4990       }
4991     }
4992     /* Interior faces have 2 vertices and 2 cells */
4993     for (c = cStart; c < cEnd; ++c) {
4994       const PetscInt *cone;
4995       PetscInt        coneNew[2], supportNew[2];
4996 
4997       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4998       for (r = 0; r < 4; ++r) {
4999         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5000 
5001         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
5002         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
5003         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5004 #if 1
5005         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5006         for (p = 0; p < 2; ++p) {
5007           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5008         }
5009 #endif
5010         supportNew[0] = (c - cStart)*4 + r;
5011         supportNew[1] = (c - cStart)*4 + (r+1)%4;
5012         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5013 #if 1
5014         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5015         for (p = 0; p < 2; ++p) {
5016           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5017         }
5018 #endif
5019       }
5020     }
5021     /* Old vertices have identical supports */
5022     for (v = vStart; v < vEnd; ++v) {
5023       const PetscInt  newp = vStartNew + (v - vStart);
5024       const PetscInt *support, *cone;
5025       PetscInt        size, s;
5026 
5027       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5028       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5029       for (s = 0; s < size; ++s) {
5030         PetscInt r = 0;
5031 
5032         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5033         if (cone[1] == v) r = 1;
5034         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5035       }
5036       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5037 #if 1
5038       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5039       for (p = 0; p < size; ++p) {
5040         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5041       }
5042 #endif
5043     }
5044     /* Face vertices have 2 + cells supports */
5045     for (f = fStart; f < fEnd; ++f) {
5046       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5047       const PetscInt *cone, *support;
5048       PetscInt        size, s;
5049 
5050       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5051       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5052       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5053       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5054       for (s = 0; s < size; ++s) {
5055         PetscInt r = 0;
5056 
5057         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5058         if      (cone[1] == f) r = 1;
5059         else if (cone[2] == f) r = 2;
5060         else if (cone[3] == f) r = 3;
5061         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
5062       }
5063       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5064 #if 1
5065       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5066       for (p = 0; p < 2+size; ++p) {
5067         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5068       }
5069 #endif
5070     }
5071     /* Cell vertices have 4 supports */
5072     for (c = cStart; c < cEnd; ++c) {
5073       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5074       PetscInt       supportNew[4];
5075 
5076       for (r = 0; r < 4; ++r) {
5077         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5078       }
5079       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5080     }
5081     break;
5082   case 3:
5083     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5084     cMax = PetscMin(cEnd, cMax);
5085     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5086     fMax = PetscMin(fEnd, fMax);
5087     /* Interior cells have 3 faces */
5088     for (c = cStart; c < cMax; ++c) {
5089       const PetscInt  newp = cStartNew + (c - cStart)*4;
5090       const PetscInt *cone, *ornt;
5091       PetscInt        coneNew[3], orntNew[3];
5092 
5093       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5094       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5095       /* A triangle */
5096       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5097       orntNew[0] = ornt[0];
5098       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
5099       orntNew[1] = -2;
5100       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5101       orntNew[2] = ornt[2];
5102       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5103       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5104 #if 1
5105       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
5106       for (p = 0; p < 3; ++p) {
5107         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5108       }
5109 #endif
5110       /* B triangle */
5111       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5112       orntNew[0] = ornt[0];
5113       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5114       orntNew[1] = ornt[1];
5115       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
5116       orntNew[2] = -2;
5117       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5118       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5119 #if 1
5120       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
5121       for (p = 0; p < 3; ++p) {
5122         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5123       }
5124 #endif
5125       /* C triangle */
5126       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
5127       orntNew[0] = -2;
5128       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5129       orntNew[1] = ornt[1];
5130       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5131       orntNew[2] = ornt[2];
5132       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5133       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5134 #if 1
5135       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
5136       for (p = 0; p < 3; ++p) {
5137         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5138       }
5139 #endif
5140       /* D triangle */
5141       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
5142       orntNew[0] = 0;
5143       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
5144       orntNew[1] = 0;
5145       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
5146       orntNew[2] = 0;
5147       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5148       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5149 #if 1
5150       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
5151       for (p = 0; p < 3; ++p) {
5152         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5153       }
5154 #endif
5155     }
5156     /*
5157      2----3----3
5158      |         |
5159      |    B    |
5160      |         |
5161      0----4--- 1
5162      |         |
5163      |    A    |
5164      |         |
5165      0----2----1
5166      */
5167     /* Hybrid cells have 4 faces */
5168     for (c = cMax; c < cEnd; ++c) {
5169       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
5170       const PetscInt *cone, *ornt;
5171       PetscInt        coneNew[4], orntNew[4];
5172 
5173       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5174       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5175       /* A quad */
5176       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5177       orntNew[0] = ornt[0];
5178       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5179       orntNew[1] = ornt[1];
5180       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
5181       orntNew[2] = 0;
5182       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
5183       orntNew[3] = 0;
5184       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5185       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5186 #if 1
5187       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
5188       for (p = 0; p < 4; ++p) {
5189         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5190       }
5191 #endif
5192       /* B quad */
5193       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5194       orntNew[0] = ornt[0];
5195       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5196       orntNew[1] = ornt[1];
5197       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
5198       orntNew[2] = 0;
5199       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
5200       orntNew[3] = 0;
5201       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5202       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5203 #if 1
5204       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
5205       for (p = 0; p < 4; ++p) {
5206         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5207       }
5208 #endif
5209     }
5210     /* Interior split faces have 2 vertices and the same cells as the parent */
5211     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5212     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5213     for (f = fStart; f < fMax; ++f) {
5214       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5215 
5216       for (r = 0; r < 2; ++r) {
5217         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5218         const PetscInt *cone, *support;
5219         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5220 
5221         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5222         coneNew[0]       = vStartNew + (cone[0] - vStart);
5223         coneNew[1]       = vStartNew + (cone[1] - vStart);
5224         coneNew[(r+1)%2] = newv;
5225         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5226 #if 1
5227         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5228         for (p = 0; p < 2; ++p) {
5229           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5230         }
5231 #endif
5232         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5233         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5234         for (s = 0; s < supportSize; ++s) {
5235           if (support[s] >= cMax) {
5236             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
5237           } else {
5238             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5239             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5240             for (c = 0; c < coneSize; ++c) {
5241               if (cone[c] == f) break;
5242             }
5243             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5244           }
5245         }
5246         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5247 #if 1
5248         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5249         for (p = 0; p < supportSize; ++p) {
5250           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
5251         }
5252 #endif
5253       }
5254     }
5255     /* Interior cell faces have 2 vertices and 2 cells */
5256     for (c = cStart; c < cMax; ++c) {
5257       const PetscInt *cone;
5258 
5259       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5260       for (r = 0; r < 3; ++r) {
5261         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5262         PetscInt       coneNew[2];
5263         PetscInt       supportNew[2];
5264 
5265         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5266         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5267         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5268 #if 1
5269         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5270         for (p = 0; p < 2; ++p) {
5271           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5272         }
5273 #endif
5274         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5275         supportNew[1] = (c - cStart)*4 + 3;
5276         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5277 #if 1
5278         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5279         for (p = 0; p < 2; ++p) {
5280           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5281         }
5282 #endif
5283       }
5284     }
5285     /* Interior hybrid faces have 2 vertices and the same cells */
5286     for (f = fMax; f < fEnd; ++f) {
5287       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5288       const PetscInt *cone;
5289       const PetscInt *support;
5290       PetscInt        coneNew[2];
5291       PetscInt        supportNew[2];
5292       PetscInt        size, s, r;
5293 
5294       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5295       coneNew[0] = vStartNew + (cone[0] - vStart);
5296       coneNew[1] = vStartNew + (cone[1] - vStart);
5297       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5298 #if 1
5299       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5300       for (p = 0; p < 2; ++p) {
5301         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5302       }
5303 #endif
5304       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5305       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5306       for (s = 0; s < size; ++s) {
5307         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5308         for (r = 0; r < 2; ++r) {
5309           if (cone[r+2] == f) break;
5310         }
5311         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
5312       }
5313       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5314 #if 1
5315       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5316       for (p = 0; p < size; ++p) {
5317         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5318       }
5319 #endif
5320     }
5321     /* Cell hybrid faces have 2 vertices and 2 cells */
5322     for (c = cMax; c < cEnd; ++c) {
5323       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5324       const PetscInt *cone;
5325       PetscInt        coneNew[2];
5326       PetscInt        supportNew[2];
5327 
5328       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5329       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
5330       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
5331       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5332 #if 1
5333       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5334       for (p = 0; p < 2; ++p) {
5335         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5336       }
5337 #endif
5338       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
5339       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
5340       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5341 #if 1
5342       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5343       for (p = 0; p < 2; ++p) {
5344         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5345       }
5346 #endif
5347     }
5348     /* Old vertices have identical supports */
5349     for (v = vStart; v < vEnd; ++v) {
5350       const PetscInt  newp = vStartNew + (v - vStart);
5351       const PetscInt *support, *cone;
5352       PetscInt        size, s;
5353 
5354       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5355       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5356       for (s = 0; s < size; ++s) {
5357         if (support[s] >= fMax) {
5358           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
5359         } else {
5360           PetscInt r = 0;
5361 
5362           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5363           if (cone[1] == v) r = 1;
5364           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5365         }
5366       }
5367       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5368 #if 1
5369       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5370       for (p = 0; p < size; ++p) {
5371         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5372       }
5373 #endif
5374     }
5375     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5376     for (f = fStart; f < fMax; ++f) {
5377       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5378       const PetscInt *cone, *support;
5379       PetscInt        size, newSize = 2, s;
5380 
5381       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5382       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5383       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5384       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5385       for (s = 0; s < size; ++s) {
5386         PetscInt r = 0;
5387 
5388         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5389         if (support[s] >= cMax) {
5390           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
5391 
5392           newSize += 1;
5393         } else {
5394           if      (cone[1] == f) r = 1;
5395           else if (cone[2] == f) r = 2;
5396           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5397           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
5398 
5399           newSize += 2;
5400         }
5401       }
5402       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5403 #if 1
5404       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5405       for (p = 0; p < newSize; ++p) {
5406         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5407       }
5408 #endif
5409     }
5410     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5411     break;
5412   default:
5413     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5414   }
5415   PetscFunctionReturn(0);
5416 }
5417 
5418 #undef __FUNCT__
5419 #define __FUNCT__ "CellRefinerSetCoordinates"
5420 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5421 {
5422   PetscSection   coordSection, coordSectionNew;
5423   Vec            coordinates, coordinatesNew;
5424   PetscScalar   *coords, *coordsNew;
5425   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
5426   PetscErrorCode ierr;
5427 
5428   PetscFunctionBegin;
5429   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5430   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5431   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5432   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5433   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5434   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
5435   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5436   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5437   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5438   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5439   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5440   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
5441   if (fMax < 0) fMax = fEnd;
5442   switch (refiner) {
5443   case 1:
5444   case 2:
5445   case 3:
5446     /* Simplicial and Hex 2D */
5447     /* All vertices have the dim coordinates */
5448     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5449       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5450       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5451     }
5452     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5453     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5454     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5455     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5456     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5457     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5458     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5459     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5460     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5461     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5462     /* Old vertices have the same coordinates */
5463     for (v = vStart; v < vEnd; ++v) {
5464       const PetscInt newv = vStartNew + (v - vStart);
5465       PetscInt       off, offnew, d;
5466 
5467       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5468       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5469       for (d = 0; d < dim; ++d) {
5470         coordsNew[offnew+d] = coords[off+d];
5471       }
5472     }
5473     /* Face vertices have the average of endpoint coordinates */
5474     for (f = fStart; f < fMax; ++f) {
5475       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5476       const PetscInt *cone;
5477       PetscInt        coneSize, offA, offB, offnew, d;
5478 
5479       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5480       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5481       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5482       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5483       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5484       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5485       for (d = 0; d < dim; ++d) {
5486         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5487       }
5488     }
5489     /* Just Hex 2D */
5490     if (refiner == 2) {
5491       /* Cell vertices have the average of corner coordinates */
5492       for (c = cStart; c < cEnd; ++c) {
5493         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5494         PetscInt      *cone = NULL;
5495         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5496 
5497         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5498         for (p = 0; p < closureSize*2; p += 2) {
5499           const PetscInt point = cone[p];
5500           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5501         }
5502         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5503         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5504         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5505         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5506         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5507         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5508         for (d = 0; d < dim; ++d) {
5509           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5510         }
5511         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5512       }
5513     }
5514     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5515     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5516     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5517     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5518     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5519     break;
5520   default:
5521     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5522   }
5523   PetscFunctionReturn(0);
5524 }
5525 
5526 #undef __FUNCT__
5527 #define __FUNCT__ "DMPlexCreateProcessSF"
5528 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5529 {
5530   PetscInt           numRoots, numLeaves, l;
5531   const PetscInt    *localPoints;
5532   const PetscSFNode *remotePoints;
5533   PetscInt          *localPointsNew;
5534   PetscSFNode       *remotePointsNew;
5535   PetscInt          *ranks, *ranksNew;
5536   PetscErrorCode     ierr;
5537 
5538   PetscFunctionBegin;
5539   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5540   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5541   for (l = 0; l < numLeaves; ++l) {
5542     ranks[l] = remotePoints[l].rank;
5543   }
5544   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5545   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
5546   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5547   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5548   for (l = 0; l < numLeaves; ++l) {
5549     ranksNew[l]              = ranks[l];
5550     localPointsNew[l]        = l;
5551     remotePointsNew[l].index = 0;
5552     remotePointsNew[l].rank  = ranksNew[l];
5553   }
5554   ierr = PetscFree(ranks);CHKERRQ(ierr);
5555   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5556   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5557   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5558   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5559   PetscFunctionReturn(0);
5560 }
5561 
5562 #undef __FUNCT__
5563 #define __FUNCT__ "CellRefinerCreateSF"
5564 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5565 {
5566   PetscSF            sf, sfNew, sfProcess;
5567   IS                 processRanks;
5568   MPI_Datatype       depthType;
5569   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5570   const PetscInt    *localPoints, *neighbors;
5571   const PetscSFNode *remotePoints;
5572   PetscInt          *localPointsNew;
5573   PetscSFNode       *remotePointsNew;
5574   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5575   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
5576   PetscErrorCode     ierr;
5577 
5578   PetscFunctionBegin;
5579   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5580   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5581   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5582   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5583   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5584   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5585   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5586   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5587   switch (refiner) {
5588   case 3:
5589     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5590     cMax = PetscMin(cEnd, cMax);
5591     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5592     fMax = PetscMin(fEnd, fMax);
5593   }
5594   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5595   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5596   /* Caculate size of new SF */
5597   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5598   if (numRoots < 0) PetscFunctionReturn(0);
5599   for (l = 0; l < numLeaves; ++l) {
5600     const PetscInt p = localPoints[l];
5601 
5602     switch (refiner) {
5603     case 1:
5604       /* Simplicial 2D */
5605       if ((p >= vStart) && (p < vEnd)) {
5606         /* Old vertices stay the same */
5607         ++numLeavesNew;
5608       } else if ((p >= fStart) && (p < fEnd)) {
5609         /* Old faces add new faces and vertex */
5610         numLeavesNew += 1 + 2;
5611       } else if ((p >= cStart) && (p < cEnd)) {
5612         /* Old cells add new cells and interior faces */
5613         numLeavesNew += 4 + 3;
5614       }
5615       break;
5616     case 2:
5617       /* Hex 2D */
5618       if ((p >= vStart) && (p < vEnd)) {
5619         /* Old vertices stay the same */
5620         ++numLeavesNew;
5621       } else if ((p >= fStart) && (p < fEnd)) {
5622         /* Old faces add new faces and vertex */
5623         numLeavesNew += 1 + 2;
5624       } else if ((p >= cStart) && (p < cEnd)) {
5625         /* Old cells add new cells and interior faces */
5626         numLeavesNew += 4 + 4;
5627       }
5628       break;
5629     default:
5630       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5631     }
5632   }
5633   /* Communicate depthSizes for each remote rank */
5634   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5635   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5636   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
5637   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);
5638   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5639   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5640   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5641   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5642   for (n = 0; n < numNeighbors; ++n) {
5643     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5644   }
5645   depthSizeOld[depth]   = cMax;
5646   depthSizeOld[0]       = vMax;
5647   depthSizeOld[depth-1] = fMax;
5648   depthSizeOld[1]       = eMax;
5649 
5650   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5651   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5652 
5653   depthSizeOld[depth]   = cEnd - cStart;
5654   depthSizeOld[0]       = vEnd - vStart;
5655   depthSizeOld[depth-1] = fEnd - fStart;
5656   depthSizeOld[1]       = eEnd - eStart;
5657 
5658   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5659   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5660   for (n = 0; n < numNeighbors; ++n) {
5661     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5662   }
5663   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5664   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5665   /* Calculate new point SF */
5666   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5667   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5668   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5669   for (l = 0, m = 0; l < numLeaves; ++l) {
5670     PetscInt    p     = localPoints[l];
5671     PetscInt    rp    = remotePoints[l].index, n;
5672     PetscMPIInt rrank = remotePoints[l].rank;
5673 
5674     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5675     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5676     switch (refiner) {
5677     case 1:
5678       /* Simplicial 2D */
5679       if ((p >= vStart) && (p < vEnd)) {
5680         /* Old vertices stay the same */
5681         localPointsNew[m]        = vStartNew     + (p  - vStart);
5682         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5683         remotePointsNew[m].rank  = rrank;
5684         ++m;
5685       } else if ((p >= fStart) && (p < fEnd)) {
5686         /* Old faces add new faces and vertex */
5687         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5688         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5689         remotePointsNew[m].rank  = rrank;
5690         ++m;
5691         for (r = 0; r < 2; ++r, ++m) {
5692           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5693           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5694           remotePointsNew[m].rank  = rrank;
5695         }
5696       } else if ((p >= cStart) && (p < cEnd)) {
5697         /* Old cells add new cells and interior faces */
5698         for (r = 0; r < 4; ++r, ++m) {
5699           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5700           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5701           remotePointsNew[m].rank  = rrank;
5702         }
5703         for (r = 0; r < 3; ++r, ++m) {
5704           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5705           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5706           remotePointsNew[m].rank  = rrank;
5707         }
5708       }
5709       break;
5710     case 2:
5711       /* Hex 2D */
5712       if ((p >= vStart) && (p < vEnd)) {
5713         /* Old vertices stay the same */
5714         localPointsNew[m]        = vStartNew     + (p  - vStart);
5715         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5716         remotePointsNew[m].rank  = rrank;
5717         ++m;
5718       } else if ((p >= fStart) && (p < fEnd)) {
5719         /* Old faces add new faces and vertex */
5720         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5721         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5722         remotePointsNew[m].rank  = rrank;
5723         ++m;
5724         for (r = 0; r < 2; ++r, ++m) {
5725           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5726           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5727           remotePointsNew[m].rank  = rrank;
5728         }
5729       } else if ((p >= cStart) && (p < cEnd)) {
5730         /* Old cells add new cells and interior faces */
5731         for (r = 0; r < 4; ++r, ++m) {
5732           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5733           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5734           remotePointsNew[m].rank  = rrank;
5735         }
5736         for (r = 0; r < 4; ++r, ++m) {
5737           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5738           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5739           remotePointsNew[m].rank  = rrank;
5740         }
5741       }
5742       break;
5743     case 3:
5744       /* Hybrid simplicial 2D */
5745       if ((p >= vStart) && (p < vEnd)) {
5746         /* Old vertices stay the same */
5747         localPointsNew[m]        = vStartNew     + (p  - vStart);
5748         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5749         remotePointsNew[m].rank  = rrank;
5750         ++m;
5751       } else if ((p >= fStart) && (p < fMax)) {
5752         /* Old interior faces add new faces and vertex */
5753         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5754         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5755         remotePointsNew[m].rank  = rrank;
5756         ++m;
5757         for (r = 0; r < 2; ++r, ++m) {
5758           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5759           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5760           remotePointsNew[m].rank  = rrank;
5761         }
5762       } else if ((p >= fMax) && (p < fEnd)) {
5763         /* Old hybrid faces stay the same */
5764         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5765         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5766         remotePointsNew[m].rank  = rrank;
5767         ++m;
5768       } else if ((p >= cStart) && (p < cMax)) {
5769         /* Old interior cells add new cells and interior faces */
5770         for (r = 0; r < 4; ++r, ++m) {
5771           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5772           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5773           remotePointsNew[m].rank  = rrank;
5774         }
5775         for (r = 0; r < 3; ++r, ++m) {
5776           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5777           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5778           remotePointsNew[m].rank  = rrank;
5779         }
5780       } else if ((p >= cStart) && (p < cMax)) {
5781         /* Old hybrid cells add new cells and hybrid face */
5782         for (r = 0; r < 2; ++r, ++m) {
5783           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5784           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5785           remotePointsNew[m].rank  = rrank;
5786         }
5787         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5788         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]);
5789         remotePointsNew[m].rank  = rrank;
5790         ++m;
5791       }
5792       break;
5793     default:
5794       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5795     }
5796   }
5797   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5798   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5799   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5800   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5801   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5802   PetscFunctionReturn(0);
5803 }
5804 
5805 #undef __FUNCT__
5806 #define __FUNCT__ "CellRefinerCreateLabels"
5807 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5808 {
5809   PetscInt       numLabels, l;
5810   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
5811   PetscErrorCode ierr;
5812 
5813   PetscFunctionBegin;
5814   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5815   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5816   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5817   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5818 
5819   cStartNew = 0;
5820   vStartNew = depthSize[2];
5821   fStartNew = depthSize[2] + depthSize[0];
5822 
5823   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5824   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5825   switch (refiner) {
5826   case 3:
5827     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5828     cMax = PetscMin(cEnd, cMax);
5829     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5830     fMax = PetscMin(fEnd, fMax);
5831   }
5832   for (l = 0; l < numLabels; ++l) {
5833     DMLabel         label, labelNew;
5834     const char     *lname;
5835     PetscBool       isDepth;
5836     IS              valueIS;
5837     const PetscInt *values;
5838     PetscInt        numValues, val;
5839 
5840     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5841     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5842     if (isDepth) continue;
5843     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5844     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5845     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5846     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5847     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5848     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5849     for (val = 0; val < numValues; ++val) {
5850       IS              pointIS;
5851       const PetscInt *points;
5852       PetscInt        numPoints, n;
5853 
5854       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5855       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5856       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5857       for (n = 0; n < numPoints; ++n) {
5858         const PetscInt p = points[n];
5859         switch (refiner) {
5860         case 1:
5861           /* Simplicial 2D */
5862           if ((p >= vStart) && (p < vEnd)) {
5863             /* Old vertices stay the same */
5864             newp = vStartNew + (p - vStart);
5865             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5866           } else if ((p >= fStart) && (p < fEnd)) {
5867             /* Old faces add new faces and vertex */
5868             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5869             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5870             for (r = 0; r < 2; ++r) {
5871               newp = fStartNew + (p - fStart)*2 + r;
5872               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5873             }
5874           } else if ((p >= cStart) && (p < cEnd)) {
5875             /* Old cells add new cells and interior faces */
5876             for (r = 0; r < 4; ++r) {
5877               newp = cStartNew + (p - cStart)*4 + r;
5878               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5879             }
5880             for (r = 0; r < 3; ++r) {
5881               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5882               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5883             }
5884           }
5885           break;
5886         case 2:
5887           /* Hex 2D */
5888           if ((p >= vStart) && (p < vEnd)) {
5889             /* Old vertices stay the same */
5890             newp = vStartNew + (p - vStart);
5891             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5892           } else if ((p >= fStart) && (p < fEnd)) {
5893             /* Old faces add new faces and vertex */
5894             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5895             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5896             for (r = 0; r < 2; ++r) {
5897               newp = fStartNew + (p - fStart)*2 + r;
5898               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5899             }
5900           } else if ((p >= cStart) && (p < cEnd)) {
5901             /* Old cells add new cells and interior faces and vertex */
5902             for (r = 0; r < 4; ++r) {
5903               newp = cStartNew + (p - cStart)*4 + r;
5904               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5905             }
5906             for (r = 0; r < 4; ++r) {
5907               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5908               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5909             }
5910             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5911             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5912           }
5913           break;
5914         case 3:
5915           /* Hybrid simplicial 2D */
5916           if ((p >= vStart) && (p < vEnd)) {
5917             /* Old vertices stay the same */
5918             newp = vStartNew + (p - vStart);
5919             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5920           } else if ((p >= fStart) && (p < fMax)) {
5921             /* Old interior faces add new faces and vertex */
5922             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5923             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5924             for (r = 0; r < 2; ++r) {
5925               newp = fStartNew + (p - fStart)*2 + r;
5926               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5927             }
5928           } else if ((p >= fMax) && (p < fEnd)) {
5929             /* Old hybrid faces stay the same */
5930             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5931             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5932           } else if ((p >= cStart) && (p < cMax)) {
5933             /* Old interior cells add new cells and interior faces */
5934             for (r = 0; r < 4; ++r) {
5935               newp = cStartNew + (p - cStart)*4 + r;
5936               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5937             }
5938             for (r = 0; r < 3; ++r) {
5939               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5940               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5941             }
5942           } else if ((p >= cMax) && (p < cEnd)) {
5943             /* Old hybrid cells add new cells and hybrid face */
5944             for (r = 0; r < 2; ++r) {
5945               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5946               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5947             }
5948             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5949             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5950           }
5951           break;
5952         default:
5953           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5954         }
5955       }
5956       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
5957       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5958     }
5959     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
5960     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
5961     if (0) {
5962       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
5963       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5964       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5965     }
5966   }
5967   PetscFunctionReturn(0);
5968 }
5969 
5970 #undef __FUNCT__
5971 #define __FUNCT__ "DMPlexRefine_Uniform"
5972 /* This will only work for interpolated meshes */
5973 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
5974 {
5975   DM             rdm;
5976   PetscInt      *depthSize;
5977   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
5978   PetscErrorCode ierr;
5979 
5980   PetscFunctionBegin;
5981   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
5982   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
5983   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5984   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
5985   /* Calculate number of new points of each depth */
5986   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5987   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
5988   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
5989   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
5990   /* Step 1: Set chart */
5991   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
5992   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
5993   /* Step 2: Set cone/support sizes */
5994   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5995   /* Step 3: Setup refined DM */
5996   ierr = DMSetUp(rdm);CHKERRQ(ierr);
5997   /* Step 4: Set cones and supports */
5998   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5999   /* Step 5: Stratify */
6000   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6001   /* Step 6: Set coordinates for vertices */
6002   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6003   /* Step 7: Create pointSF */
6004   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6005   /* Step 8: Create labels */
6006   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6007   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6008 
6009   *dmRefined = rdm;
6010   PetscFunctionReturn(0);
6011 }
6012 
6013 #undef __FUNCT__
6014 #define __FUNCT__ "DMPlexSetRefinementUniform"
6015 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6016 {
6017   DM_Plex *mesh = (DM_Plex*) dm->data;
6018 
6019   PetscFunctionBegin;
6020   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6021   mesh->refinementUniform = refinementUniform;
6022   PetscFunctionReturn(0);
6023 }
6024 
6025 #undef __FUNCT__
6026 #define __FUNCT__ "DMPlexGetRefinementUniform"
6027 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6028 {
6029   DM_Plex *mesh = (DM_Plex*) dm->data;
6030 
6031   PetscFunctionBegin;
6032   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6033   PetscValidPointer(refinementUniform,  2);
6034   *refinementUniform = mesh->refinementUniform;
6035   PetscFunctionReturn(0);
6036 }
6037 
6038 #undef __FUNCT__
6039 #define __FUNCT__ "DMPlexSetRefinementLimit"
6040 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6041 {
6042   DM_Plex *mesh = (DM_Plex*) dm->data;
6043 
6044   PetscFunctionBegin;
6045   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6046   mesh->refinementLimit = refinementLimit;
6047   PetscFunctionReturn(0);
6048 }
6049 
6050 #undef __FUNCT__
6051 #define __FUNCT__ "DMPlexGetRefinementLimit"
6052 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6053 {
6054   DM_Plex *mesh = (DM_Plex*) dm->data;
6055 
6056   PetscFunctionBegin;
6057   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6058   PetscValidPointer(refinementLimit,  2);
6059   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6060   *refinementLimit = mesh->refinementLimit;
6061   PetscFunctionReturn(0);
6062 }
6063 
6064 #undef __FUNCT__
6065 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
6066 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
6067 {
6068   PetscInt       dim, cStart, coneSize, cMax;
6069   PetscErrorCode ierr;
6070 
6071   PetscFunctionBegin;
6072   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6073   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
6074   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6075   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6076   switch (dim) {
6077   case 2:
6078     switch (coneSize) {
6079     case 3:
6080       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
6081       else *cellRefiner = 1; /* Triangular */
6082       break;
6083     case 4:
6084       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
6085       else *cellRefiner = 2; /* Quadrilateral */
6086       break;
6087     default:
6088       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6089     }
6090     break;
6091   default:
6092     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6093   }
6094   PetscFunctionReturn(0);
6095 }
6096 
6097 #undef __FUNCT__
6098 #define __FUNCT__ "DMRefine_Plex"
6099 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
6100 {
6101   PetscReal      refinementLimit;
6102   PetscInt       dim, cStart, cEnd;
6103   char           genname[1024], *name = NULL;
6104   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
6105   PetscErrorCode ierr;
6106 
6107   PetscFunctionBegin;
6108   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
6109   if (isUniform) {
6110     CellRefiner cellRefiner;
6111 
6112     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
6113     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
6114     PetscFunctionReturn(0);
6115   }
6116   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
6117   if (refinementLimit == 0.0) PetscFunctionReturn(0);
6118   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6119   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6120   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
6121   if (flg) name = genname;
6122   if (name) {
6123     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
6124     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
6125     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
6126   }
6127   switch (dim) {
6128   case 2:
6129     if (!name || isTriangle) {
6130 #if defined(PETSC_HAVE_TRIANGLE)
6131       double  *maxVolumes;
6132       PetscInt c;
6133 
6134       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
6135       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
6136       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6137 #else
6138       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
6139 #endif
6140     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
6141     break;
6142   case 3:
6143     if (!name || isCTetgen) {
6144 #if defined(PETSC_HAVE_CTETGEN)
6145       PetscReal *maxVolumes;
6146       PetscInt   c;
6147 
6148       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
6149       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
6150       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6151 #else
6152       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
6153 #endif
6154     } else if (isTetgen) {
6155 #if defined(PETSC_HAVE_TETGEN)
6156       double  *maxVolumes;
6157       PetscInt c;
6158 
6159       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
6160       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
6161       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6162 #else
6163       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
6164 #endif
6165     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
6166     break;
6167   default:
6168     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
6169   }
6170   PetscFunctionReturn(0);
6171 }
6172 
6173 #undef __FUNCT__
6174 #define __FUNCT__ "DMPlexGetDepth"
6175 /*@
6176   DMPlexGetDepth - get the number of strata
6177 
6178   Not Collective
6179 
6180   Input Parameters:
6181 . dm           - The DMPlex object
6182 
6183   Output Parameters:
6184 . depth - number of strata
6185 
6186   Level: developer
6187 
6188   Notes:
6189   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
6190 
6191 .keywords: mesh, points
6192 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
6193 @*/
6194 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
6195 {
6196   PetscInt       d;
6197   PetscErrorCode ierr;
6198 
6199   PetscFunctionBegin;
6200   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6201   PetscValidPointer(depth, 2);
6202   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
6203   *depth = d-1;
6204   PetscFunctionReturn(0);
6205 }
6206 
6207 #undef __FUNCT__
6208 #define __FUNCT__ "DMPlexGetDepthStratum"
6209 /*@
6210   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
6211 
6212   Not Collective
6213 
6214   Input Parameters:
6215 + dm           - The DMPlex object
6216 - stratumValue - The requested depth
6217 
6218   Output Parameters:
6219 + start - The first point at this depth
6220 - end   - One beyond the last point at this depth
6221 
6222   Level: developer
6223 
6224 .keywords: mesh, points
6225 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
6226 @*/
6227 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
6228 {
6229   DM_Plex       *mesh = (DM_Plex*) dm->data;
6230   DMLabel        next  = mesh->labels;
6231   PetscBool      flg   = PETSC_FALSE;
6232   PetscInt       depth;
6233   PetscErrorCode ierr;
6234 
6235   PetscFunctionBegin;
6236   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6237   if (stratumValue < 0) {
6238     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6239     PetscFunctionReturn(0);
6240   } else {
6241     PetscInt pStart, pEnd;
6242 
6243     if (start) *start = 0;
6244     if (end)   *end   = 0;
6245     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6246     if (pStart == pEnd) PetscFunctionReturn(0);
6247   }
6248   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
6249   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6250   /* We should have a generic GetLabel() and a Label class */
6251   while (next) {
6252     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
6253     if (flg) break;
6254     next = next->next;
6255   }
6256   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6257   depth = stratumValue;
6258   if ((depth < 0) || (depth >= next->numStrata)) {
6259     if (start) *start = 0;
6260     if (end)   *end   = 0;
6261   } else {
6262     if (start) *start = next->points[next->stratumOffsets[depth]];
6263     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
6264   }
6265   PetscFunctionReturn(0);
6266 }
6267 
6268 #undef __FUNCT__
6269 #define __FUNCT__ "DMPlexGetHeightStratum"
6270 /*@
6271   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
6272 
6273   Not Collective
6274 
6275   Input Parameters:
6276 + dm           - The DMPlex object
6277 - stratumValue - The requested height
6278 
6279   Output Parameters:
6280 + start - The first point at this height
6281 - end   - One beyond the last point at this height
6282 
6283   Level: developer
6284 
6285 .keywords: mesh, points
6286 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
6287 @*/
6288 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
6289 {
6290   DM_Plex       *mesh = (DM_Plex*) dm->data;
6291   DMLabel        next  = mesh->labels;
6292   PetscBool      flg   = PETSC_FALSE;
6293   PetscInt       depth;
6294   PetscErrorCode ierr;
6295 
6296   PetscFunctionBegin;
6297   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6298   if (stratumValue < 0) {
6299     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6300   } else {
6301     PetscInt pStart, pEnd;
6302 
6303     if (start) *start = 0;
6304     if (end)   *end   = 0;
6305     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6306     if (pStart == pEnd) PetscFunctionReturn(0);
6307   }
6308   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
6309   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6310   /* We should have a generic GetLabel() and a Label class */
6311   while (next) {
6312     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
6313     if (flg) break;
6314     next = next->next;
6315   }
6316   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6317   depth = next->stratumValues[next->numStrata-1] - stratumValue;
6318   if ((depth < 0) || (depth >= next->numStrata)) {
6319     if (start) *start = 0;
6320     if (end)   *end   = 0;
6321   } else {
6322     if (start) *start = next->points[next->stratumOffsets[depth]];
6323     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
6324   }
6325   PetscFunctionReturn(0);
6326 }
6327 
6328 #undef __FUNCT__
6329 #define __FUNCT__ "DMPlexCreateSectionInitial"
6330 /* Set the number of dof on each point and separate by fields */
6331 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
6332 {
6333   PetscInt      *numDofTot;
6334   PetscInt       pStart = 0, pEnd = 0;
6335   PetscInt       p, d, f;
6336   PetscErrorCode ierr;
6337 
6338   PetscFunctionBegin;
6339   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
6340   for (d = 0; d <= dim; ++d) {
6341     numDofTot[d] = 0;
6342     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
6343   }
6344   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
6345   if (numFields > 0) {
6346     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
6347     if (numComp) {
6348       for (f = 0; f < numFields; ++f) {
6349         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
6350       }
6351     }
6352   }
6353   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6354   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
6355   for (d = 0; d <= dim; ++d) {
6356     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
6357     for (p = pStart; p < pEnd; ++p) {
6358       for (f = 0; f < numFields; ++f) {
6359         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
6360       }
6361       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
6362     }
6363   }
6364   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
6365   PetscFunctionReturn(0);
6366 }
6367 
6368 #undef __FUNCT__
6369 #define __FUNCT__ "DMPlexCreateSectionBCDof"
6370 /* Set the number of dof on each point and separate by fields
6371    If constDof is PETSC_DETERMINE, constrain every dof on the point
6372 */
6373 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
6374 {
6375   PetscInt       numFields;
6376   PetscInt       bc;
6377   PetscErrorCode ierr;
6378 
6379   PetscFunctionBegin;
6380   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6381   for (bc = 0; bc < numBC; ++bc) {
6382     PetscInt        field = 0;
6383     const PetscInt *idx;
6384     PetscInt        n, i;
6385 
6386     if (numFields) field = bcField[bc];
6387     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
6388     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6389     for (i = 0; i < n; ++i) {
6390       const PetscInt p        = idx[i];
6391       PetscInt       numConst = constDof;
6392 
6393       /* Constrain every dof on the point */
6394       if (numConst < 0) {
6395         if (numFields) {
6396           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
6397         } else {
6398           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
6399         }
6400       }
6401       if (numFields) {
6402         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
6403       }
6404       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
6405     }
6406     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6407   }
6408   PetscFunctionReturn(0);
6409 }
6410 
6411 #undef __FUNCT__
6412 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
6413 /* Set the constrained indices on each point and separate by fields */
6414 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
6415 {
6416   PetscInt      *maxConstraints;
6417   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
6418   PetscErrorCode ierr;
6419 
6420   PetscFunctionBegin;
6421   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6422   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6423   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
6424   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
6425   for (p = pStart; p < pEnd; ++p) {
6426     PetscInt cdof;
6427 
6428     if (numFields) {
6429       for (f = 0; f < numFields; ++f) {
6430         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
6431         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
6432       }
6433     } else {
6434       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6435       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
6436     }
6437   }
6438   for (f = 0; f < numFields; ++f) {
6439     maxConstraints[numFields] += maxConstraints[f];
6440   }
6441   if (maxConstraints[numFields]) {
6442     PetscInt *indices;
6443 
6444     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6445     for (p = pStart; p < pEnd; ++p) {
6446       PetscInt cdof, d;
6447 
6448       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6449       if (cdof) {
6450         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
6451         if (numFields) {
6452           PetscInt numConst = 0, foff = 0;
6453 
6454           for (f = 0; f < numFields; ++f) {
6455             PetscInt cfdof, fdof;
6456 
6457             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6458             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
6459             /* Change constraint numbering from absolute local dof number to field relative local dof number */
6460             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
6461             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
6462             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
6463             numConst += cfdof;
6464             foff     += fdof;
6465           }
6466           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6467         } else {
6468           for (d = 0; d < cdof; ++d) indices[d] = d;
6469         }
6470         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6471       }
6472     }
6473     ierr = PetscFree(indices);CHKERRQ(ierr);
6474   }
6475   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
6476   PetscFunctionReturn(0);
6477 }
6478 
6479 #undef __FUNCT__
6480 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
6481 /* Set the constrained field indices on each point */
6482 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
6483 {
6484   const PetscInt *points, *indices;
6485   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
6486   PetscErrorCode  ierr;
6487 
6488   PetscFunctionBegin;
6489   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6490   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
6491 
6492   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
6493   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
6494   if (!constraintIndices) {
6495     PetscInt *idx, i;
6496 
6497     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6498     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
6499     for (i = 0; i < maxDof; ++i) idx[i] = i;
6500     for (p = 0; p < numPoints; ++p) {
6501       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
6502     }
6503     ierr = PetscFree(idx);CHKERRQ(ierr);
6504   } else {
6505     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
6506     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
6507     for (p = 0; p < numPoints; ++p) {
6508       PetscInt fcdof;
6509 
6510       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
6511       if (fcdof != numConstraints) SETERRQ4(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
6512       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
6513     }
6514     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
6515   }
6516   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
6517   PetscFunctionReturn(0);
6518 }
6519 
6520 #undef __FUNCT__
6521 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
6522 /* Set the constrained indices on each point and separate by fields */
6523 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
6524 {
6525   PetscInt      *indices;
6526   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
6527   PetscErrorCode ierr;
6528 
6529   PetscFunctionBegin;
6530   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6531   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6532   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6533   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
6534   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6535   for (p = pStart; p < pEnd; ++p) {
6536     PetscInt cdof, d;
6537 
6538     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6539     if (cdof) {
6540       PetscInt numConst = 0, foff = 0;
6541 
6542       for (f = 0; f < numFields; ++f) {
6543         const PetscInt *fcind;
6544         PetscInt        fdof, fcdof;
6545 
6546         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6547         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
6548         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
6549         /* Change constraint numbering from field relative local dof number to absolute local dof number */
6550         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
6551         foff     += fdof;
6552         numConst += fcdof;
6553       }
6554       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6555       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6556     }
6557   }
6558   ierr = PetscFree(indices);CHKERRQ(ierr);
6559   PetscFunctionReturn(0);
6560 }
6561 
6562 #undef __FUNCT__
6563 #define __FUNCT__ "DMPlexCreateSection"
6564 /*@C
6565   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
6566 
6567   Not Collective
6568 
6569   Input Parameters:
6570 + dm        - The DMPlex object
6571 . dim       - The spatial dimension of the problem
6572 . numFields - The number of fields in the problem
6573 . numComp   - An array of size numFields that holds the number of components for each field
6574 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
6575 . numBC     - The number of boundary conditions
6576 . bcField   - An array of size numBC giving the field number for each boundry condition
6577 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
6578 
6579   Output Parameter:
6580 . section - The PetscSection object
6581 
6582   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
6583   nubmer of dof for field 0 on each edge.
6584 
6585   Level: developer
6586 
6587 .keywords: mesh, elements
6588 .seealso: DMPlexCreate(), PetscSectionCreate()
6589 @*/
6590 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
6591 {
6592   PetscErrorCode ierr;
6593 
6594   PetscFunctionBegin;
6595   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
6596   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
6597   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
6598   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
6599   {
6600     PetscBool view = PETSC_FALSE;
6601 
6602     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
6603     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
6604   }
6605   PetscFunctionReturn(0);
6606 }
6607 
6608 #undef __FUNCT__
6609 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
6610 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
6611 {
6612   PetscSection   section;
6613   PetscErrorCode ierr;
6614 
6615   PetscFunctionBegin;
6616   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
6617   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6618   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
6619   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6620   PetscFunctionReturn(0);
6621 }
6622 
6623 #undef __FUNCT__
6624 #define __FUNCT__ "DMPlexGetCoordinateSection"
6625 /*@
6626   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6627 
6628   Not Collective
6629 
6630   Input Parameter:
6631 . dm - The DMPlex object
6632 
6633   Output Parameter:
6634 . section - The PetscSection object
6635 
6636   Level: intermediate
6637 
6638 .keywords: mesh, coordinates
6639 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6640 @*/
6641 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
6642 {
6643   DM             cdm;
6644   PetscErrorCode ierr;
6645 
6646   PetscFunctionBegin;
6647   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6648   PetscValidPointer(section, 2);
6649   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6650   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
6651   PetscFunctionReturn(0);
6652 }
6653 
6654 #undef __FUNCT__
6655 #define __FUNCT__ "DMPlexSetCoordinateSection"
6656 /*@
6657   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
6658 
6659   Not Collective
6660 
6661   Input Parameters:
6662 + dm      - The DMPlex object
6663 - section - The PetscSection object
6664 
6665   Level: intermediate
6666 
6667 .keywords: mesh, coordinates
6668 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6669 @*/
6670 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
6671 {
6672   DM             cdm;
6673   PetscErrorCode ierr;
6674 
6675   PetscFunctionBegin;
6676   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6677   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
6678   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6679   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
6680   PetscFunctionReturn(0);
6681 }
6682 
6683 #undef __FUNCT__
6684 #define __FUNCT__ "DMPlexGetConeSection"
6685 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
6686 {
6687   DM_Plex *mesh = (DM_Plex*) dm->data;
6688 
6689   PetscFunctionBegin;
6690   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6691   if (section) *section = mesh->coneSection;
6692   PetscFunctionReturn(0);
6693 }
6694 
6695 #undef __FUNCT__
6696 #define __FUNCT__ "DMPlexGetCones"
6697 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
6698 {
6699   DM_Plex *mesh = (DM_Plex*) dm->data;
6700 
6701   PetscFunctionBegin;
6702   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6703   if (cones) *cones = mesh->cones;
6704   PetscFunctionReturn(0);
6705 }
6706 
6707 #undef __FUNCT__
6708 #define __FUNCT__ "DMPlexGetConeOrientations"
6709 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
6710 {
6711   DM_Plex *mesh = (DM_Plex*) dm->data;
6712 
6713   PetscFunctionBegin;
6714   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6715   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
6716   PetscFunctionReturn(0);
6717 }
6718 
6719 #undef __FUNCT__
6720 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
6721 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
6722 {
6723   const PetscInt embedDim = 2;
6724   PetscReal      x        = PetscRealPart(point[0]);
6725   PetscReal      y        = PetscRealPart(point[1]);
6726   PetscReal      v0[2], J[4], invJ[4], detJ;
6727   PetscReal      xi, eta;
6728   PetscErrorCode ierr;
6729 
6730   PetscFunctionBegin;
6731   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
6732   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
6733   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
6734 
6735   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
6736   else *cell = -1;
6737   PetscFunctionReturn(0);
6738 }
6739 
6740 #undef __FUNCT__
6741 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
6742 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
6743 {
6744   PetscSection       coordSection;
6745   Vec                coordsLocal;
6746   const PetscScalar *coords;
6747   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
6748   PetscReal          x         = PetscRealPart(point[0]);
6749   PetscReal          y         = PetscRealPart(point[1]);
6750   PetscInt           crossings = 0, f;
6751   PetscErrorCode     ierr;
6752 
6753   PetscFunctionBegin;
6754   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
6755   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6756   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
6757   for (f = 0; f < 4; ++f) {
6758     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
6759     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
6760     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
6761     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
6762     PetscReal slope = (y_j - y_i) / (x_j - x_i);
6763     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
6764     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
6765     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
6766     if ((cond1 || cond2)  && above) ++crossings;
6767   }
6768   if (crossings % 2) *cell = c;
6769   else *cell = -1;
6770   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
6771   PetscFunctionReturn(0);
6772 }
6773 
6774 #undef __FUNCT__
6775 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
6776 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
6777 {
6778   const PetscInt embedDim = 3;
6779   PetscReal      v0[3], J[9], invJ[9], detJ;
6780   PetscReal      x = PetscRealPart(point[0]);
6781   PetscReal      y = PetscRealPart(point[1]);
6782   PetscReal      z = PetscRealPart(point[2]);
6783   PetscReal      xi, eta, zeta;
6784   PetscErrorCode ierr;
6785 
6786   PetscFunctionBegin;
6787   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
6788   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
6789   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
6790   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
6791 
6792   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
6793   else *cell = -1;
6794   PetscFunctionReturn(0);
6795 }
6796 
6797 #undef __FUNCT__
6798 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
6799 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
6800 {
6801   PetscSection       coordSection;
6802   Vec                coordsLocal;
6803   const PetscScalar *coords;
6804   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
6805                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
6806   PetscBool          found = PETSC_TRUE;
6807   PetscInt           f;
6808   PetscErrorCode     ierr;
6809 
6810   PetscFunctionBegin;
6811   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
6812   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6813   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
6814   for (f = 0; f < 6; ++f) {
6815     /* Check the point is under plane */
6816     /*   Get face normal */
6817     PetscReal v_i[3];
6818     PetscReal v_j[3];
6819     PetscReal normal[3];
6820     PetscReal pp[3];
6821     PetscReal dot;
6822 
6823     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
6824     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
6825     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
6826     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
6827     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
6828     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
6829     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
6830     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
6831     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
6832     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
6833     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
6834     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
6835     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
6836 
6837     /* Check that projected point is in face (2D location problem) */
6838     if (dot < 0.0) {
6839       found = PETSC_FALSE;
6840       break;
6841     }
6842   }
6843   if (found) *cell = c;
6844   else *cell = -1;
6845   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
6846   PetscFunctionReturn(0);
6847 }
6848 
6849 #undef __FUNCT__
6850 #define __FUNCT__ "DMLocatePoints_Plex"
6851 /*
6852  Need to implement using the guess
6853 */
6854 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
6855 {
6856   PetscInt       cell = -1 /*, guess = -1*/;
6857   PetscInt       bs, numPoints, p;
6858   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
6859   PetscInt      *cells;
6860   PetscScalar   *a;
6861   PetscErrorCode ierr;
6862 
6863   PetscFunctionBegin;
6864   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6865   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6866   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6867   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
6868   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
6869   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
6870   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
6871   if (bs != dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
6872   numPoints /= bs;
6873   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
6874   for (p = 0; p < numPoints; ++p) {
6875     const PetscScalar *point = &a[p*bs];
6876 
6877     switch (dim) {
6878     case 2:
6879       for (c = cStart; c < cEnd; ++c) {
6880         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6881         switch (coneSize) {
6882         case 3:
6883           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
6884           break;
6885         case 4:
6886           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
6887           break;
6888         default:
6889           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
6890         }
6891         if (cell >= 0) break;
6892       }
6893       break;
6894     case 3:
6895       for (c = cStart; c < cEnd; ++c) {
6896         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6897         switch (coneSize) {
6898         case 4:
6899           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
6900           break;
6901         case 8:
6902           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
6903           break;
6904         default:
6905           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
6906         }
6907         if (cell >= 0) break;
6908       }
6909       break;
6910     default:
6911       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
6912     }
6913     cells[p] = cell;
6914   }
6915   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
6916   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
6917   PetscFunctionReturn(0);
6918 }
6919 
6920 /******************************** FEM Support **********************************/
6921 
6922 #undef __FUNCT__
6923 #define __FUNCT__ "DMPlexVecGetClosure"
6924 /*@C
6925   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6926 
6927   Not collective
6928 
6929   Input Parameters:
6930 + dm - The DM
6931 . section - The section describing the layout in v, or NULL to use the default section
6932 . v - The local vector
6933 - point - The sieve point in the DM
6934 
6935   Output Parameters:
6936 + csize - The number of values in the closure, or NULL
6937 - values - The array of values, which is a borrowed array and should not be freed
6938 
6939   Level: intermediate
6940 
6941 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6942 @*/
6943 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
6944 {
6945   PetscScalar   *array, *vArray;
6946   PetscInt      *points = NULL;
6947   PetscInt       offsets[32];
6948   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
6949   PetscErrorCode ierr;
6950 
6951   PetscFunctionBegin;
6952   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6953   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6954   if (!section) {
6955     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6956   }
6957   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6958   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6959   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6960   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6961   /* Compress out points not in the section */
6962   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6963   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6964     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6965       points[q*2]   = points[p];
6966       points[q*2+1] = points[p+1];
6967       ++q;
6968     }
6969   }
6970   numPoints = q;
6971   for (p = 0, size = 0; p < numPoints*2; p += 2) {
6972     PetscInt dof, fdof;
6973 
6974     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6975     for (f = 0; f < numFields; ++f) {
6976       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6977       offsets[f+1] += fdof;
6978     }
6979     size += dof;
6980   }
6981   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6982   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
6983   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
6984   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
6985   for (p = 0; p < numPoints*2; p += 2) {
6986     PetscInt     o = points[p+1];
6987     PetscInt     dof, off, d;
6988     PetscScalar *varr;
6989 
6990     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6991     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
6992     varr = &vArray[off];
6993     if (numFields) {
6994       PetscInt fdof, foff, fcomp, f, c;
6995 
6996       for (f = 0, foff = 0; f < numFields; ++f) {
6997         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6998         if (o >= 0) {
6999           for (d = 0; d < fdof; ++d, ++offsets[f]) {
7000             array[offsets[f]] = varr[foff+d];
7001           }
7002         } else {
7003           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7004           for (d = fdof/fcomp-1; d >= 0; --d) {
7005             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
7006               array[offsets[f]] = varr[foff+d*fcomp+c];
7007             }
7008           }
7009         }
7010         foff += fdof;
7011       }
7012     } else {
7013       if (o >= 0) {
7014         for (d = 0; d < dof; ++d, ++offsets[0]) {
7015           array[offsets[0]] = varr[d];
7016         }
7017       } else {
7018         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
7019           array[offsets[0]] = varr[d];
7020         }
7021       }
7022     }
7023   }
7024   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7025   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
7026   if (csize) *csize = size;
7027   *values = array;
7028   PetscFunctionReturn(0);
7029 }
7030 
7031 #undef __FUNCT__
7032 #define __FUNCT__ "DMPlexVecRestoreClosure"
7033 /*@C
7034   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
7035 
7036   Not collective
7037 
7038   Input Parameters:
7039 + dm - The DM
7040 . section - The section describing the layout in v, or NULL to use the default section
7041 . v - The local vector
7042 . point - The sieve point in the DM
7043 . csize - The number of values in the closure, or NULL
7044 - values - The array of values, which is a borrowed array and should not be freed
7045 
7046   Level: intermediate
7047 
7048 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7049 @*/
7050 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
7051 {
7052   PetscInt       size = 0;
7053   PetscErrorCode ierr;
7054 
7055   PetscFunctionBegin;
7056   /* Should work without recalculating size */
7057   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
7058   PetscFunctionReturn(0);
7059 }
7060 
7061 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
7062 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
7063 
7064 #undef __FUNCT__
7065 #define __FUNCT__ "updatePoint_private"
7066 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
7067 {
7068   PetscInt        cdof;   /* The number of constraints on this point */
7069   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7070   PetscScalar    *a;
7071   PetscInt        off, cind = 0, k;
7072   PetscErrorCode  ierr;
7073 
7074   PetscFunctionBegin;
7075   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7076   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7077   a    = &array[off];
7078   if (!cdof || setBC) {
7079     if (orientation >= 0) {
7080       for (k = 0; k < dof; ++k) {
7081         fuse(&a[k], values[k]);
7082       }
7083     } else {
7084       for (k = 0; k < dof; ++k) {
7085         fuse(&a[k], values[dof-k-1]);
7086       }
7087     }
7088   } else {
7089     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7090     if (orientation >= 0) {
7091       for (k = 0; k < dof; ++k) {
7092         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7093         fuse(&a[k], values[k]);
7094       }
7095     } else {
7096       for (k = 0; k < dof; ++k) {
7097         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7098         fuse(&a[k], values[dof-k-1]);
7099       }
7100     }
7101   }
7102   PetscFunctionReturn(0);
7103 }
7104 
7105 #undef __FUNCT__
7106 #define __FUNCT__ "updatePointFields_private"
7107 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
7108 {
7109   PetscScalar   *a;
7110   PetscInt       numFields, off, foff, f;
7111   PetscErrorCode ierr;
7112 
7113   PetscFunctionBegin;
7114   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7115   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7116   a    = &array[off];
7117   for (f = 0, foff = 0; f < numFields; ++f) {
7118     PetscInt        fdof, fcomp, fcdof;
7119     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7120     PetscInt        cind = 0, k, c;
7121 
7122     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7123     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7124     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
7125     if (!fcdof || setBC) {
7126       if (orientation >= 0) {
7127         for (k = 0; k < fdof; ++k) {
7128           fuse(&a[foff+k], values[foffs[f]+k]);
7129         }
7130       } else {
7131         for (k = fdof/fcomp-1; k >= 0; --k) {
7132           for (c = 0; c < fcomp; ++c) {
7133             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7134           }
7135         }
7136       }
7137     } else {
7138       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7139       if (orientation >= 0) {
7140         for (k = 0; k < fdof; ++k) {
7141           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
7142           fuse(&a[foff+k], values[foffs[f]+k]);
7143         }
7144       } else {
7145         for (k = fdof/fcomp-1; k >= 0; --k) {
7146           for (c = 0; c < fcomp; ++c) {
7147             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
7148             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7149           }
7150         }
7151       }
7152     }
7153     foff     += fdof;
7154     foffs[f] += fdof;
7155   }
7156   PetscFunctionReturn(0);
7157 }
7158 
7159 #undef __FUNCT__
7160 #define __FUNCT__ "DMPlexVecSetClosure"
7161 /*@C
7162   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
7163 
7164   Not collective
7165 
7166   Input Parameters:
7167 + dm - The DM
7168 . section - The section describing the layout in v, or NULL to use the default sectionw
7169 . v - The local vector
7170 . point - The sieve point in the DM
7171 . values - The array of values, which is a borrowed array and should not be freed
7172 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7173 
7174   Level: intermediate
7175 
7176 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
7177 @*/
7178 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7179 {
7180   PetscScalar   *array;
7181   PetscInt      *points = NULL;
7182   PetscInt       offsets[32];
7183   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
7184   PetscErrorCode ierr;
7185 
7186   PetscFunctionBegin;
7187   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7188   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7189   if (!section) {
7190     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7191   }
7192   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7193   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7194   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7195   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7196   /* Compress out points not in the section */
7197   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7198   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7199     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7200       points[q*2]   = points[p];
7201       points[q*2+1] = points[p+1];
7202       ++q;
7203     }
7204   }
7205   numPoints = q;
7206   for (p = 0; p < numPoints*2; p += 2) {
7207     PetscInt fdof;
7208 
7209     for (f = 0; f < numFields; ++f) {
7210       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7211       offsets[f+1] += fdof;
7212     }
7213   }
7214   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7215   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
7216   if (numFields) {
7217     switch (mode) {
7218     case INSERT_VALUES:
7219       for (p = 0; p < numPoints*2; p += 2) {
7220         PetscInt o = points[p+1];
7221         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
7222       } break;
7223     case INSERT_ALL_VALUES:
7224       for (p = 0; p < numPoints*2; p += 2) {
7225         PetscInt o = points[p+1];
7226         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
7227       } break;
7228     case ADD_VALUES:
7229       for (p = 0; p < numPoints*2; p += 2) {
7230         PetscInt o = points[p+1];
7231         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
7232       } break;
7233     case ADD_ALL_VALUES:
7234       for (p = 0; p < numPoints*2; p += 2) {
7235         PetscInt o = points[p+1];
7236         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
7237       } break;
7238     default:
7239       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7240     }
7241   } else {
7242     switch (mode) {
7243     case INSERT_VALUES:
7244       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7245         PetscInt o = points[p+1];
7246         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7247         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
7248       } break;
7249     case INSERT_ALL_VALUES:
7250       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7251         PetscInt o = points[p+1];
7252         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7253         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
7254       } break;
7255     case ADD_VALUES:
7256       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7257         PetscInt o = points[p+1];
7258         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7259         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
7260       } break;
7261     case ADD_ALL_VALUES:
7262       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7263         PetscInt o = points[p+1];
7264         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7265         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
7266       } break;
7267     default:
7268       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7269     }
7270   }
7271   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7272   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
7273   PetscFunctionReturn(0);
7274 }
7275 
7276 #undef __FUNCT__
7277 #define __FUNCT__ "DMPlexPrintMatSetValues"
7278 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
7279 {
7280   PetscMPIInt    rank;
7281   PetscInt       i, j;
7282   PetscErrorCode ierr;
7283 
7284   PetscFunctionBegin;
7285   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
7286   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
7287   for (i = 0; i < numIndices; i++) {
7288     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
7289   }
7290   for (i = 0; i < numIndices; i++) {
7291     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
7292     for (j = 0; j < numIndices; j++) {
7293 #if defined(PETSC_USE_COMPLEX)
7294       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
7295 #else
7296       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
7297 #endif
7298     }
7299     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
7300   }
7301   PetscFunctionReturn(0);
7302 }
7303 
7304 #undef __FUNCT__
7305 #define __FUNCT__ "indicesPoint_private"
7306 /* . off - The global offset of this point */
7307 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
7308 {
7309   PetscInt        dof;    /* The number of unknowns on this point */
7310   PetscInt        cdof;   /* The number of constraints on this point */
7311   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7312   PetscInt        cind = 0, k;
7313   PetscErrorCode  ierr;
7314 
7315   PetscFunctionBegin;
7316   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
7317   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7318   if (!cdof || setBC) {
7319     if (orientation >= 0) {
7320       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
7321     } else {
7322       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
7323     }
7324   } else {
7325     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7326     if (orientation >= 0) {
7327       for (k = 0; k < dof; ++k) {
7328         if ((cind < cdof) && (k == cdofs[cind])) {
7329           /* Insert check for returning constrained indices */
7330           indices[*loff+k] = -(off+k+1);
7331           ++cind;
7332         } else {
7333           indices[*loff+k] = off+k-cind;
7334         }
7335       }
7336     } else {
7337       for (k = 0; k < dof; ++k) {
7338         if ((cind < cdof) && (k == cdofs[cind])) {
7339           /* Insert check for returning constrained indices */
7340           indices[*loff+dof-k-1] = -(off+k+1);
7341           ++cind;
7342         } else {
7343           indices[*loff+dof-k-1] = off+k-cind;
7344         }
7345       }
7346     }
7347   }
7348   *loff += dof;
7349   PetscFunctionReturn(0);
7350 }
7351 
7352 #undef __FUNCT__
7353 #define __FUNCT__ "indicesPointFields_private"
7354 /* . off - The global offset of this point */
7355 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
7356 {
7357   PetscInt       numFields, foff, f;
7358   PetscErrorCode ierr;
7359 
7360   PetscFunctionBegin;
7361   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7362   for (f = 0, foff = 0; f < numFields; ++f) {
7363     PetscInt        fdof, fcomp, cfdof;
7364     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7365     PetscInt        cind = 0, k, c;
7366 
7367     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7368     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7369     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
7370     if (!cfdof || setBC) {
7371       if (orientation >= 0) {
7372         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
7373       } else {
7374         for (k = fdof/fcomp-1; k >= 0; --k) {
7375           for (c = 0; c < fcomp; ++c) {
7376             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
7377           }
7378         }
7379       }
7380     } else {
7381       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7382       if (orientation >= 0) {
7383         for (k = 0; k < fdof; ++k) {
7384           if ((cind < cfdof) && (k == fcdofs[cind])) {
7385             indices[foffs[f]+k] = -(off+foff+k+1);
7386             ++cind;
7387           } else {
7388             indices[foffs[f]+k] = off+foff+k-cind;
7389           }
7390         }
7391       } else {
7392         for (k = fdof/fcomp-1; k >= 0; --k) {
7393           for (c = 0; c < fcomp; ++c) {
7394             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
7395               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
7396               ++cind;
7397             } else {
7398               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
7399             }
7400           }
7401         }
7402       }
7403     }
7404     foff     += fdof - cfdof;
7405     foffs[f] += fdof;
7406   }
7407   PetscFunctionReturn(0);
7408 }
7409 
7410 #undef __FUNCT__
7411 #define __FUNCT__ "DMPlexMatSetClosure"
7412 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
7413 {
7414   DM_Plex       *mesh   = (DM_Plex*) dm->data;
7415   PetscInt      *points = NULL;
7416   PetscInt      *indices;
7417   PetscInt       offsets[32];
7418   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
7419   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
7420   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
7421   PetscErrorCode ierr;
7422 
7423   PetscFunctionBegin;
7424   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7425   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
7426   if (useDefault) {
7427     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7428   }
7429   if (useGlobalDefault) {
7430     if (useDefault) {
7431       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
7432     } else {
7433       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7434     }
7435   }
7436   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7437   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7438   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7439   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7440   /* Compress out points not in the section */
7441   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7442   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7443     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7444       points[q*2]   = points[p];
7445       points[q*2+1] = points[p+1];
7446       ++q;
7447     }
7448   }
7449   numPoints = q;
7450   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
7451     PetscInt fdof;
7452 
7453     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7454     for (f = 0; f < numFields; ++f) {
7455       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7456       offsets[f+1] += fdof;
7457     }
7458     numIndices += dof;
7459   }
7460   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7461 
7462   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
7463   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7464   if (numFields) {
7465     for (p = 0; p < numPoints*2; p += 2) {
7466       PetscInt o = points[p+1];
7467       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
7468       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
7469     }
7470   } else {
7471     for (p = 0, off = 0; p < numPoints*2; p += 2) {
7472       PetscInt o = points[p+1];
7473       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
7474       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
7475     }
7476   }
7477   if (useGlobalDefault && !useDefault) {
7478     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7479   }
7480   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
7481   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7482   if (ierr) {
7483     PetscMPIInt    rank;
7484     PetscErrorCode ierr2;
7485 
7486     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
7487     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7488     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
7489     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
7490     CHKERRQ(ierr);
7491   }
7492   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7493   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7494   PetscFunctionReturn(0);
7495 }
7496 
7497 #undef __FUNCT__
7498 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
7499 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
7500 {
7501   PetscSection       coordSection;
7502   Vec                coordinates;
7503   const PetscScalar *coords;
7504   const PetscInt     dim = 2;
7505   PetscInt           d, f;
7506   PetscErrorCode     ierr;
7507 
7508   PetscFunctionBegin;
7509   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7510   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7511   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7512   if (v0) {
7513     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
7514   }
7515   if (J) {
7516     for (d = 0; d < dim; d++) {
7517       for (f = 0; f < dim; f++) {
7518         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7519       }
7520     }
7521     *detJ = J[0]*J[3] - J[1]*J[2];
7522 #if 0
7523     if (detJ < 0.0) {
7524       const PetscReal xLength = mesh->periodicity[0];
7525 
7526       if (xLength != 0.0) {
7527         PetscReal v0x = coords[0*dim+0];
7528 
7529         if (v0x == 0.0) v0x = v0[0] = xLength;
7530         for (f = 0; f < dim; f++) {
7531           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
7532 
7533           J[0*dim+f] = 0.5*(px - v0x);
7534         }
7535       }
7536       detJ = J[0]*J[3] - J[1]*J[2];
7537     }
7538 #endif
7539     PetscLogFlops(8.0 + 3.0);
7540   }
7541   if (invJ) {
7542     const PetscReal invDet = 1.0/(*detJ);
7543 
7544     invJ[0] =  invDet*J[3];
7545     invJ[1] = -invDet*J[1];
7546     invJ[2] = -invDet*J[2];
7547     invJ[3] =  invDet*J[0];
7548     PetscLogFlops(5.0);
7549   }
7550   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7551   PetscFunctionReturn(0);
7552 }
7553 
7554 #undef __FUNCT__
7555 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
7556 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
7557 {
7558   PetscSection       coordSection;
7559   Vec                coordinates;
7560   const PetscScalar *coords;
7561   const PetscInt     dim = 2;
7562   PetscInt           d, f;
7563   PetscErrorCode     ierr;
7564 
7565   PetscFunctionBegin;
7566   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7567   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7568   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7569   if (v0) {
7570     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
7571   }
7572   if (J) {
7573     for (d = 0; d < dim; d++) {
7574       for (f = 0; f < dim; f++) {
7575         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7576       }
7577     }
7578     *detJ = J[0]*J[3] - J[1]*J[2];
7579     PetscLogFlops(8.0 + 3.0);
7580   }
7581   if (invJ) {
7582     const PetscReal invDet = 1.0/(*detJ);
7583 
7584     invJ[0] =  invDet*J[3];
7585     invJ[1] = -invDet*J[1];
7586     invJ[2] = -invDet*J[2];
7587     invJ[3] =  invDet*J[0];
7588     PetscLogFlops(5.0);
7589   }
7590   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7591   PetscFunctionReturn(0);
7592 }
7593 
7594 #undef __FUNCT__
7595 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
7596 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
7597 {
7598   PetscSection       coordSection;
7599   Vec                coordinates;
7600   const PetscScalar *coords;
7601   const PetscInt     dim = 3;
7602   PetscInt           d, f;
7603   PetscErrorCode     ierr;
7604 
7605   PetscFunctionBegin;
7606   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7607   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7608   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7609   if (v0) {
7610     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
7611   }
7612   if (J) {
7613     for (d = 0; d < dim; d++) {
7614       for (f = 0; f < dim; f++) {
7615         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7616       }
7617     }
7618     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
7619     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
7620              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
7621              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
7622     PetscLogFlops(18.0 + 12.0);
7623   }
7624   if (invJ) {
7625     const PetscReal invDet = 1.0/(*detJ);
7626 
7627     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
7628     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
7629     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
7630     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
7631     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
7632     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
7633     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
7634     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
7635     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
7636     PetscLogFlops(37.0);
7637   }
7638   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7639   PetscFunctionReturn(0);
7640 }
7641 
7642 #undef __FUNCT__
7643 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
7644 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
7645 {
7646   PetscSection       coordSection;
7647   Vec                coordinates;
7648   const PetscScalar *coords;
7649   const PetscInt     dim = 3;
7650   PetscInt           d;
7651   PetscErrorCode     ierr;
7652 
7653   PetscFunctionBegin;
7654   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7655   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7656   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7657   if (v0) {
7658     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
7659   }
7660   if (J) {
7661     for (d = 0; d < dim; d++) {
7662       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7663       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7664       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
7665     }
7666     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
7667              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
7668              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
7669     PetscLogFlops(18.0 + 12.0);
7670   }
7671   if (invJ) {
7672     const PetscReal invDet = -1.0/(*detJ);
7673 
7674     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
7675     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
7676     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
7677     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
7678     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
7679     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
7680     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
7681     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
7682     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
7683     PetscLogFlops(37.0);
7684   }
7685   *detJ *= 8.0;
7686   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
7687   PetscFunctionReturn(0);
7688 }
7689 
7690 #undef __FUNCT__
7691 #define __FUNCT__ "DMPlexComputeCellGeometry"
7692 /*@C
7693   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
7694 
7695   Collective on DM
7696 
7697   Input Arguments:
7698 + dm   - the DM
7699 - cell - the cell
7700 
7701   Output Arguments:
7702 + v0   - the translation part of this affine transform
7703 . J    - the Jacobian of the transform to the reference element
7704 . invJ - the inverse of the Jacobian
7705 - detJ - the Jacobian determinant
7706 
7707   Level: advanced
7708 
7709 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
7710 @*/
7711 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
7712 {
7713   PetscInt       dim, coneSize;
7714   PetscErrorCode ierr;
7715 
7716   PetscFunctionBegin;
7717   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7718   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
7719   switch (dim) {
7720   case 2:
7721     switch (coneSize) {
7722     case 3:
7723       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
7724       break;
7725     case 4:
7726       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
7727       break;
7728     default:
7729       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
7730     }
7731     break;
7732   case 3:
7733     switch (coneSize) {
7734     case 4:
7735       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
7736       break;
7737     case 8:
7738       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
7739       break;
7740     default:
7741       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
7742     }
7743     break;
7744   default:
7745     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
7746   }
7747   PetscFunctionReturn(0);
7748 }
7749 
7750 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
7751 {
7752   switch (i) {
7753   case 0:
7754     switch (j) {
7755     case 0: return 0;
7756     case 1:
7757       switch (k) {
7758       case 0: return 0;
7759       case 1: return 0;
7760       case 2: return 1;
7761       }
7762     case 2:
7763       switch (k) {
7764       case 0: return 0;
7765       case 1: return -1;
7766       case 2: return 0;
7767       }
7768     }
7769   case 1:
7770     switch (j) {
7771     case 0:
7772       switch (k) {
7773       case 0: return 0;
7774       case 1: return 0;
7775       case 2: return -1;
7776       }
7777     case 1: return 0;
7778     case 2:
7779       switch (k) {
7780       case 0: return 1;
7781       case 1: return 0;
7782       case 2: return 0;
7783       }
7784     }
7785   case 2:
7786     switch (j) {
7787     case 0:
7788       switch (k) {
7789       case 0: return 0;
7790       case 1: return 1;
7791       case 2: return 0;
7792       }
7793     case 1:
7794       switch (k) {
7795       case 0: return -1;
7796       case 1: return 0;
7797       case 2: return 0;
7798       }
7799     case 2: return 0;
7800     }
7801   }
7802   return 0;
7803 }
7804 
7805 #undef __FUNCT__
7806 #define __FUNCT__ "DMPlexCreateRigidBody"
7807 /*@C
7808   DMPlexCreateRigidBody - create rigid body modes from coordinates
7809 
7810   Collective on DM
7811 
7812   Input Arguments:
7813 + dm - the DM
7814 . section - the local section associated with the rigid field, or NULL for the default section
7815 - globalSection - the global section associated with the rigid field, or NULL for the default section
7816 
7817   Output Argument:
7818 . sp - the null space
7819 
7820   Note: This is necessary to take account of Dirichlet conditions on the displacements
7821 
7822   Level: advanced
7823 
7824 .seealso: MatNullSpaceCreate()
7825 @*/
7826 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
7827 {
7828   MPI_Comm       comm;
7829   Vec            coordinates, localMode, mode[6];
7830   PetscSection   coordSection;
7831   PetscScalar   *coords;
7832   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
7833   PetscErrorCode ierr;
7834 
7835   PetscFunctionBegin;
7836   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
7837   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7838   if (dim == 1) {
7839     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
7840     PetscFunctionReturn(0);
7841   }
7842   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
7843   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
7844   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
7845   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7846   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7847   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7848   m    = (dim*(dim+1))/2;
7849   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
7850   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
7851   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
7852   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
7853   /* Assume P1 */
7854   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
7855   for (d = 0; d < dim; ++d) {
7856     PetscScalar values[3] = {0.0, 0.0, 0.0};
7857 
7858     values[d] = 1.0;
7859     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
7860     for (v = vStart; v < vEnd; ++v) {
7861       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
7862     }
7863     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
7864     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
7865   }
7866   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
7867   for (d = dim; d < dim*(dim+1)/2; ++d) {
7868     PetscInt i, j, k = dim > 2 ? d - dim : d;
7869 
7870     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
7871     for (v = vStart; v < vEnd; ++v) {
7872       PetscScalar values[3] = {0.0, 0.0, 0.0};
7873       PetscInt    off;
7874 
7875       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
7876       for (i = 0; i < dim; ++i) {
7877         for (j = 0; j < dim; ++j) {
7878           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
7879         }
7880       }
7881       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
7882     }
7883     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
7884     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
7885   }
7886   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
7887   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
7888   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
7889   /* Orthonormalize system */
7890   for (i = dim; i < m; ++i) {
7891     PetscScalar dots[6];
7892 
7893     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
7894     for (j = 0; j < i; ++j) dots[j] *= -1.0;
7895     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
7896     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
7897   }
7898   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
7899   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
7900   PetscFunctionReturn(0);
7901 }
7902 
7903 #undef __FUNCT__
7904 #define __FUNCT__ "DMPlexGetHybridBounds"
7905 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
7906 {
7907   DM_Plex       *mesh = (DM_Plex*) dm->data;
7908   PetscInt       dim;
7909   PetscErrorCode ierr;
7910 
7911   PetscFunctionBegin;
7912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7913   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7914   if (cMax) *cMax = mesh->hybridPointMax[dim];
7915   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
7916   if (eMax) *eMax = mesh->hybridPointMax[1];
7917   if (vMax) *vMax = mesh->hybridPointMax[0];
7918   PetscFunctionReturn(0);
7919 }
7920 
7921 #undef __FUNCT__
7922 #define __FUNCT__ "DMPlexSetHybridBounds"
7923 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
7924 {
7925   DM_Plex       *mesh = (DM_Plex*) dm->data;
7926   PetscInt       dim;
7927   PetscErrorCode ierr;
7928 
7929   PetscFunctionBegin;
7930   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7931   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7932   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
7933   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
7934   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
7935   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
7936   PetscFunctionReturn(0);
7937 }
7938 
7939 #undef __FUNCT__
7940 #define __FUNCT__ "DMPlexGetVTKCellHeight"
7941 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7942 {
7943   DM_Plex *mesh = (DM_Plex*) dm->data;
7944 
7945   PetscFunctionBegin;
7946   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7947   PetscValidPointer(cellHeight, 2);
7948   *cellHeight = mesh->vtkCellHeight;
7949   PetscFunctionReturn(0);
7950 }
7951 
7952 #undef __FUNCT__
7953 #define __FUNCT__ "DMPlexSetVTKCellHeight"
7954 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7955 {
7956   DM_Plex *mesh = (DM_Plex*) dm->data;
7957 
7958   PetscFunctionBegin;
7959   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7960   mesh->vtkCellHeight = cellHeight;
7961   PetscFunctionReturn(0);
7962 }
7963 
7964 #undef __FUNCT__
7965 #define __FUNCT__ "DMPlexCreateNumbering_Private"
7966 /* We can easily have a form that takes an IS instead */
7967 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
7968 {
7969   PetscSection   section, globalSection;
7970   PetscInt      *numbers, p;
7971   PetscErrorCode ierr;
7972 
7973   PetscFunctionBegin;
7974   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7975   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
7976   for (p = pStart; p < pEnd; ++p) {
7977     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
7978   }
7979   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
7980   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7981   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
7982   for (p = pStart; p < pEnd; ++p) {
7983     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
7984   }
7985   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
7986   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7987   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7988   PetscFunctionReturn(0);
7989 }
7990 
7991 #undef __FUNCT__
7992 #define __FUNCT__ "DMPlexGetCellNumbering"
7993 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
7994 {
7995   DM_Plex       *mesh = (DM_Plex*) dm->data;
7996   PetscInt       cellHeight, cStart, cEnd, cMax;
7997   PetscErrorCode ierr;
7998 
7999   PetscFunctionBegin;
8000   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8001   if (!mesh->globalCellNumbers) {
8002     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8003     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8004     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
8005     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8006     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
8007   }
8008   *globalCellNumbers = mesh->globalCellNumbers;
8009   PetscFunctionReturn(0);
8010 }
8011 
8012 #undef __FUNCT__
8013 #define __FUNCT__ "DMPlexGetVertexNumbering"
8014 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8015 {
8016   DM_Plex       *mesh = (DM_Plex*) dm->data;
8017   PetscInt       vStart, vEnd, vMax;
8018   PetscErrorCode ierr;
8019 
8020   PetscFunctionBegin;
8021   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8022   if (!mesh->globalVertexNumbers) {
8023     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8024     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
8025     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
8026     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
8027   }
8028   *globalVertexNumbers = mesh->globalVertexNumbers;
8029   PetscFunctionReturn(0);
8030 }
8031 
8032 #undef __FUNCT__
8033 #define __FUNCT__ "DMPlexGetScale"
8034 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
8035 {
8036   DM_Plex *mesh = (DM_Plex*) dm->data;
8037 
8038   PetscFunctionBegin;
8039   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8040   PetscValidPointer(scale, 3);
8041   *scale = mesh->scale[unit];
8042   PetscFunctionReturn(0);
8043 }
8044 
8045 #undef __FUNCT__
8046 #define __FUNCT__ "DMPlexSetScale"
8047 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
8048 {
8049   DM_Plex *mesh = (DM_Plex*) dm->data;
8050 
8051   PetscFunctionBegin;
8052   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8053   mesh->scale[unit] = scale;
8054   PetscFunctionReturn(0);
8055 }
8056 
8057 
8058 /*******************************************************************************
8059 This should be in a separate Discretization object, but I am not sure how to lay
8060 it out yet, so I am stuffing things here while I experiment.
8061 *******************************************************************************/
8062 #undef __FUNCT__
8063 #define __FUNCT__ "DMPlexSetFEMIntegration"
8064 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
8065                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
8066                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
8067                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8068                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
8069                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
8070                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
8071                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8072                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8073                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8074                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
8075                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
8076                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
8077                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8078                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8079                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
8080                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
8081 {
8082   DM_Plex *mesh = (DM_Plex*) dm->data;
8083 
8084   PetscFunctionBegin;
8085   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8086   mesh->integrateResidualFEM       = integrateResidualFEM;
8087   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
8088   mesh->integrateJacobianFEM       = integrateJacobianFEM;
8089   PetscFunctionReturn(0);
8090 }
8091 
8092 #undef __FUNCT__
8093 #define __FUNCT__ "DMPlexProjectFunctionLocal"
8094 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
8095 {
8096   Vec            coordinates;
8097   PetscSection   section, cSection;
8098   PetscInt       dim, vStart, vEnd, v, c, d;
8099   PetscScalar   *values, *cArray;
8100   PetscReal     *coords;
8101   PetscErrorCode ierr;
8102 
8103   PetscFunctionBegin;
8104   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8105   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8106   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
8107   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8108   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
8109   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
8110   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
8111   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
8112   for (v = vStart; v < vEnd; ++v) {
8113     PetscInt dof, off;
8114 
8115     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
8116     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
8117     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
8118     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
8119     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
8120     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
8121   }
8122   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
8123   /* Temporary, must be replaced by a projection on the finite element basis */
8124   {
8125     PetscInt eStart = 0, eEnd = 0, e, depth;
8126 
8127     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
8128     --depth;
8129     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
8130     for (e = eStart; e < eEnd; ++e) {
8131       const PetscInt *cone = NULL;
8132       PetscInt        coneSize, d;
8133       PetscScalar    *coordsA, *coordsB;
8134 
8135       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
8136       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8137       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
8138       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
8139       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
8140       for (d = 0; d < dim; ++d) {
8141         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
8142       }
8143       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
8144       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
8145     }
8146   }
8147 
8148   ierr = PetscFree(coords);CHKERRQ(ierr);
8149   ierr = PetscFree(values);CHKERRQ(ierr);
8150 #if 0
8151   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
8152   PetscReal      detJ;
8153 
8154   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
8155   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
8156   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
8157 
8158   for (PetscInt c = cStart; c < cEnd; ++c) {
8159     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
8160     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
8161     const int                          oSize   = pV.getSize();
8162     int                                v       = 0;
8163 
8164     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
8165     for (PetscInt cl = 0; cl < oSize; ++cl) {
8166       const PetscInt fDim;
8167 
8168       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
8169       if (pointDim) {
8170         for (PetscInt d = 0; d < fDim; ++d, ++v) {
8171           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
8172         }
8173       }
8174     }
8175     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
8176     pV.clear();
8177   }
8178   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
8179   ierr = PetscFree(values);CHKERRQ(ierr);
8180 #endif
8181   PetscFunctionReturn(0);
8182 }
8183 
8184 #undef __FUNCT__
8185 #define __FUNCT__ "DMPlexProjectFunction"
8186 /*@C
8187   DMPlexProjectFunction - This projects the given function into the function space provided.
8188 
8189   Input Parameters:
8190 + dm      - The DM
8191 . numComp - The number of components (functions)
8192 . funcs   - The coordinate functions to evaluate
8193 - mode    - The insertion mode for values
8194 
8195   Output Parameter:
8196 . X - vector
8197 
8198   Level: developer
8199 
8200   Note:
8201   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
8202   We will eventually fix it.
8203 
8204 ,seealso: DMPlexComputeL2Diff()
8205 */
8206 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
8207 {
8208   Vec            localX;
8209   PetscErrorCode ierr;
8210 
8211   PetscFunctionBegin;
8212   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
8213   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
8214   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
8215   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
8216   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
8217   PetscFunctionReturn(0);
8218 }
8219 
8220 #undef __FUNCT__
8221 #define __FUNCT__ "DMPlexComputeL2Diff"
8222 /*@C
8223   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8224 
8225   Input Parameters:
8226 + dm    - The DM
8227 . quad  - The PetscQuadrature object for each field
8228 . funcs - The functions to evaluate for each field component
8229 - X     - The coefficient vector u_h
8230 
8231   Output Parameter:
8232 . diff - The diff ||u - u_h||_2
8233 
8234   Level: developer
8235 
8236 .seealso: DMPlexProjectFunction()
8237 */
8238 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
8239 {
8240   const PetscInt debug = 0;
8241   PetscSection   section;
8242   Vec            localX;
8243   PetscReal     *coords, *v0, *J, *invJ, detJ;
8244   PetscReal      localDiff = 0.0;
8245   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
8246   PetscErrorCode ierr;
8247 
8248   PetscFunctionBegin;
8249   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8250   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8251   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8252   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
8253   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
8254   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
8255   for (field = 0; field < numFields; ++field) {
8256     numComponents += quad[field].numComponents;
8257   }
8258   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
8259   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
8260   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8261   for (c = cStart; c < cEnd; ++c) {
8262     const PetscScalar *x;
8263     PetscReal          elemDiff = 0.0;
8264 
8265     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8266     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
8267     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
8268 
8269     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
8270       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
8271       const PetscReal *quadPoints    = quad[field].quadPoints;
8272       const PetscReal *quadWeights   = quad[field].quadWeights;
8273       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
8274       const PetscInt   numBasisComps = quad[field].numComponents;
8275       const PetscReal *basis         = quad[field].basis;
8276       PetscInt         q, d, e, fc, f;
8277 
8278       if (debug) {
8279         char title[1024];
8280         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
8281         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
8282       }
8283       for (q = 0; q < numQuadPoints; ++q) {
8284         for (d = 0; d < dim; d++) {
8285           coords[d] = v0[d];
8286           for (e = 0; e < dim; e++) {
8287             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
8288           }
8289         }
8290         for (fc = 0; fc < numBasisComps; ++fc) {
8291           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
8292           PetscReal       interpolant = 0.0;
8293           for (f = 0; f < numBasisFuncs; ++f) {
8294             const PetscInt fidx = f*numBasisComps+fc;
8295             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
8296           }
8297           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
8298           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
8299         }
8300       }
8301       comp        += numBasisComps;
8302       fieldOffset += numBasisFuncs*numBasisComps;
8303     }
8304     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
8305     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
8306     localDiff += elemDiff;
8307   }
8308   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
8309   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
8310   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
8311   *diff = PetscSqrtReal(*diff);
8312   PetscFunctionReturn(0);
8313 }
8314 
8315 #undef __FUNCT__
8316 #define __FUNCT__ "DMPlexComputeResidualFEM"
8317 /*@
8318   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
8319 
8320   Input Parameters:
8321 + dm - The mesh
8322 . X  - Local input vector
8323 - user - The user context
8324 
8325   Output Parameter:
8326 . F  - Local output vector
8327 
8328   Note:
8329   The second member of the user context must be an FEMContext.
8330 
8331   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
8332   like a GPU, or vectorize on a multicore machine.
8333 
8334 .seealso: DMPlexComputeJacobianActionFEM()
8335 */
8336 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
8337 {
8338   DM_Plex         *mesh = (DM_Plex*) dm->data;
8339   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
8340   PetscQuadrature *quad = fem->quad;
8341   PetscSection     section;
8342   PetscReal       *v0, *J, *invJ, *detJ;
8343   PetscScalar     *elemVec, *u;
8344   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
8345   PetscInt         cellDof = 0, numComponents = 0;
8346   PetscErrorCode   ierr;
8347 
8348   PetscFunctionBegin;
8349   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8350   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8351   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8352   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8353   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8354   numCells = cEnd - cStart;
8355   for (field = 0; field < numFields; ++field) {
8356     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
8357     numComponents += quad[field].numComponents;
8358   }
8359   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
8360   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
8361   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);
8362   for (c = cStart; c < cEnd; ++c) {
8363     const PetscScalar *x;
8364     PetscInt           i;
8365 
8366     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
8367     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
8368     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8369 
8370     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
8371     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8372   }
8373   for (field = 0; field < numFields; ++field) {
8374     const PetscInt numQuadPoints = quad[field].numQuadPoints;
8375     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
8376     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
8377     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
8378     /* Conforming batches */
8379     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
8380     PetscInt numBlocks  = 1;
8381     PetscInt batchSize  = numBlocks * blockSize;
8382     PetscInt numBatches = numBatchesTmp;
8383     PetscInt numChunks  = numCells / (numBatches*batchSize);
8384     /* Remainder */
8385     PetscInt numRemainder = numCells % (numBatches * batchSize);
8386     PetscInt offset       = numCells - numRemainder;
8387 
8388     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
8389     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
8390                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
8391   }
8392   for (c = cStart; c < cEnd; ++c) {
8393     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
8394     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
8395   }
8396   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
8397   if (mesh->printFEM) {
8398     PetscMPIInt rank, numProcs;
8399     PetscInt    p;
8400 
8401     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
8402     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
8403     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
8404     for (p = 0; p < numProcs; ++p) {
8405       if (p == rank) {
8406         Vec f;
8407 
8408         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
8409         ierr = VecCopy(F, f);CHKERRQ(ierr);
8410         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
8411         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
8412         ierr = VecDestroy(&f);CHKERRQ(ierr);
8413         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
8414       }
8415       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
8416     }
8417   }
8418   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8419   PetscFunctionReturn(0);
8420 }
8421 
8422 #undef __FUNCT__
8423 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
8424 /*@C
8425   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
8426 
8427   Input Parameters:
8428 + dm - The mesh
8429 . J  - The Jacobian shell matrix
8430 . X  - Local input vector
8431 - user - The user context
8432 
8433   Output Parameter:
8434 . F  - Local output vector
8435 
8436   Note:
8437   The second member of the user context must be an FEMContext.
8438 
8439   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
8440   like a GPU, or vectorize on a multicore machine.
8441 
8442 .seealso: DMPlexComputeResidualFEM()
8443 */
8444 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
8445 {
8446   DM_Plex         *mesh = (DM_Plex*) dm->data;
8447   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
8448   PetscQuadrature *quad = fem->quad;
8449   PetscSection     section;
8450   JacActionCtx    *jctx;
8451   PetscReal       *v0, *J, *invJ, *detJ;
8452   PetscScalar     *elemVec, *u, *a;
8453   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
8454   PetscInt         cellDof = 0;
8455   PetscErrorCode   ierr;
8456 
8457   PetscFunctionBegin;
8458   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8459   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
8460   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8461   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8462   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8463   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8464   numCells = cEnd - cStart;
8465   for (field = 0; field < numFields; ++field) {
8466     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
8467   }
8468   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
8469   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);
8470   for (c = cStart; c < cEnd; ++c) {
8471     const PetscScalar *x;
8472     PetscInt           i;
8473 
8474     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
8475     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
8476     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
8477     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
8478     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
8479     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8480     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
8481     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8482   }
8483   for (field = 0; field < numFields; ++field) {
8484     const PetscInt numQuadPoints = quad[field].numQuadPoints;
8485     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
8486     /* Conforming batches */
8487     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
8488     PetscInt numBlocks  = 1;
8489     PetscInt batchSize  = numBlocks * blockSize;
8490     PetscInt numBatches = numBatchesTmp;
8491     PetscInt numChunks  = numCells / (numBatches*batchSize);
8492     /* Remainder */
8493     PetscInt numRemainder = numCells % (numBatches * batchSize);
8494     PetscInt offset       = numCells - numRemainder;
8495 
8496     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);
8497     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],
8498                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
8499   }
8500   for (c = cStart; c < cEnd; ++c) {
8501     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
8502     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
8503   }
8504   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
8505   if (mesh->printFEM) {
8506     PetscMPIInt rank, numProcs;
8507     PetscInt    p;
8508 
8509     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
8510     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
8511     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
8512     for (p = 0; p < numProcs; ++p) {
8513       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
8514       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
8515     }
8516   }
8517   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8518   PetscFunctionReturn(0);
8519 }
8520 
8521 #undef __FUNCT__
8522 #define __FUNCT__ "DMPlexComputeJacobianFEM"
8523 /*@
8524   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
8525 
8526   Input Parameters:
8527 + dm - The mesh
8528 . X  - Local input vector
8529 - user - The user context
8530 
8531   Output Parameter:
8532 . Jac  - Jacobian matrix
8533 
8534   Note:
8535   The second member of the user context must be an FEMContext.
8536 
8537   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
8538   like a GPU, or vectorize on a multicore machine.
8539 
8540 .seealso: FormFunctionLocal()
8541 */
8542 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
8543 {
8544   DM_Plex         *mesh = (DM_Plex*) dm->data;
8545   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
8546   PetscQuadrature *quad = fem->quad;
8547   PetscSection     section;
8548   PetscReal       *v0, *J, *invJ, *detJ;
8549   PetscScalar     *elemMat, *u;
8550   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
8551   PetscInt         cellDof = 0, numComponents = 0;
8552   PetscBool        isShell;
8553   PetscErrorCode   ierr;
8554 
8555   PetscFunctionBegin;
8556   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8557   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8558   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8559   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8560   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8561   numCells = cEnd - cStart;
8562   for (field = 0; field < numFields; ++field) {
8563     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
8564     numComponents += quad[field].numComponents;
8565   }
8566   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
8567   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
8568   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);
8569   for (c = cStart; c < cEnd; ++c) {
8570     const PetscScalar *x;
8571     PetscInt           i;
8572 
8573     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
8574     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
8575     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8576 
8577     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
8578     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
8579   }
8580   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
8581   for (fieldI = 0; fieldI < numFields; ++fieldI) {
8582     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
8583     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
8584     PetscInt       fieldJ;
8585 
8586     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
8587       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
8588       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
8589       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
8590       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
8591       /* Conforming batches */
8592       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
8593       PetscInt numBlocks  = 1;
8594       PetscInt batchSize  = numBlocks * blockSize;
8595       PetscInt numBatches = numBatchesTmp;
8596       PetscInt numChunks  = numCells / (numBatches*batchSize);
8597       /* Remainder */
8598       PetscInt numRemainder = numCells % (numBatches * batchSize);
8599       PetscInt offset       = numCells - numRemainder;
8600 
8601       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
8602       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
8603                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
8604     }
8605   }
8606   for (c = cStart; c < cEnd; ++c) {
8607     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
8608     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
8609   }
8610   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
8611 
8612   /* Assemble matrix, using the 2-step process:
8613        MatAssemblyBegin(), MatAssemblyEnd(). */
8614   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
8615   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
8616 
8617   if (mesh->printFEM) {
8618     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
8619     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
8620     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
8621   }
8622   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
8623   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
8624   if (isShell) {
8625     JacActionCtx *jctx;
8626 
8627     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
8628     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
8629   }
8630   *str = SAME_NONZERO_PATTERN;
8631   PetscFunctionReturn(0);
8632 }
8633 
8634 
8635 #undef __FUNCT__
8636 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
8637 /*@C
8638   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
8639   the local section and an SF describing the section point overlap.
8640 
8641   Input Parameters:
8642   + s - The PetscSection for the local field layout
8643   . sf - The SF describing parallel layout of the section points
8644   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
8645   . label - The label specifying the points
8646   - labelValue - The label stratum specifying the points
8647 
8648   Output Parameter:
8649   . gsection - The PetscSection for the global field layout
8650 
8651   Note: This gives negative sizes and offsets to points not owned by this process
8652 
8653   Level: developer
8654 
8655 .seealso: PetscSectionCreate()
8656 @*/
8657 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
8658 {
8659   PetscInt      *neg;
8660   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
8661   PetscErrorCode ierr;
8662 
8663   PetscFunctionBegin;
8664   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
8665   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
8666   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
8667   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
8668   /* Mark ghost points with negative dof */
8669   for (p = pStart; p < pEnd; ++p) {
8670     PetscInt value;
8671 
8672     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
8673     if (value != labelValue) continue;
8674     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
8675     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
8676     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
8677     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
8678     neg[p-pStart] = -(dof+1);
8679   }
8680   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
8681   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
8682   if (nroots >= 0) {
8683     if (nroots > pEnd - pStart) {
8684       PetscInt *tmpDof;
8685       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
8686       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
8687       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
8688       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
8689       for (p = pStart; p < pEnd; ++p) {
8690         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
8691       }
8692       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
8693     } else {
8694       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
8695       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
8696     }
8697   }
8698   /* Calculate new sizes, get proccess offset, and calculate point offsets */
8699   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
8700     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
8701 
8702     (*gsection)->atlasOff[p] = off;
8703 
8704     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
8705   }
8706   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
8707   globalOff -= off;
8708   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
8709     (*gsection)->atlasOff[p] += globalOff;
8710 
8711     neg[p] = -((*gsection)->atlasOff[p]+1);
8712   }
8713   /* Put in negative offsets for ghost points */
8714   if (nroots >= 0) {
8715     if (nroots > pEnd - pStart) {
8716       PetscInt *tmpOff;
8717       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
8718       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
8719       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
8720       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
8721       for (p = pStart; p < pEnd; ++p) {
8722         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
8723       }
8724       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
8725     } else {
8726       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
8727       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
8728     }
8729   }
8730   ierr = PetscFree(neg);CHKERRQ(ierr);
8731   PetscFunctionReturn(0);
8732 }
8733