xref: /petsc/src/dm/impls/plex/plex.c (revision 2a4c4990d51857b2e976754013cc7d755ade2a93)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/isimpl.h>
4 #include <petscsf.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       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
340     }
341   }
342   PetscFunctionReturn(0);
343 }
344 
345 #undef __FUNCT__
346 #define __FUNCT__ "DMView_Plex"
347 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
348 {
349   PetscBool      iascii, isbinary;
350   PetscErrorCode ierr;
351 
352   PetscFunctionBegin;
353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
354   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
355   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
356   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
357   if (iascii) {
358     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
359 #if 0
360   } else if (isbinary) {
361     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
362 #endif
363   }
364   PetscFunctionReturn(0);
365 }
366 
367 #undef __FUNCT__
368 #define __FUNCT__ "DMDestroy_Plex"
369 PetscErrorCode DMDestroy_Plex(DM dm)
370 {
371   DM_Plex       *mesh = (DM_Plex*) dm->data;
372   DMLabel        next  = mesh->labels;
373   PetscErrorCode ierr;
374 
375   PetscFunctionBegin;
376   if (--mesh->refct > 0) PetscFunctionReturn(0);
377   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
378   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
379   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
380   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
381   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
382   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
383   while (next) {
384     DMLabel tmp = next->next;
385 
386     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
387     next = tmp;
388   }
389   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
390   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
391   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
392   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
393   ierr = PetscFree(mesh);CHKERRQ(ierr);
394   PetscFunctionReturn(0);
395 }
396 
397 #undef __FUNCT__
398 #define __FUNCT__ "DMCreateMatrix_Plex"
399 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
400 {
401   PetscSection   section, sectionGlobal;
402   PetscInt       bs = -1;
403   PetscInt       localSize;
404   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
405   PetscErrorCode ierr;
406 
407   PetscFunctionBegin;
408 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
409   ierr = MatInitializePackage();CHKERRQ(ierr);
410 #endif
411   if (!mtype) mtype = MATAIJ;
412   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
413   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
414   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
415   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
416   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
417   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
418   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
419   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
420   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
421   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
422   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
423   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
424   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
425   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
426   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
427   /* Check for symmetric storage */
428   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
429   if (isSymmetric) {
430     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
431   }
432   if (!isShell) {
433     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
434     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
435 
436     if (bs < 0) {
437       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
438         PetscInt pStart, pEnd, p, dof, cdof;
439 
440         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
441         for (p = pStart; p < pEnd; ++p) {
442           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
443           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
444           if (dof-cdof) {
445             if (bs < 0) {
446               bs = dof-cdof;
447             } else if (bs != dof-cdof) {
448               /* Layout does not admit a pointwise block size */
449               bs = 1;
450               break;
451             }
452           }
453         }
454         /* Must have same blocksize on all procs (some might have no points) */
455         bsLocal = bs;
456         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
457         bsLocal = bs < 0 ? bsMax : bs;
458         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
459         if (bsMin != bsMax) {
460           bs = 1;
461         } else {
462           bs = bsMax;
463         }
464       } else {
465         bs = 1;
466       }
467     }
468     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
469     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
470     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
471     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
472     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
473     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
474     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
475   }
476   PetscFunctionReturn(0);
477 }
478 
479 #undef __FUNCT__
480 #define __FUNCT__ "DMPlexGetDimension"
481 /*@
482   DMPlexGetDimension - Return the topological mesh dimension
483 
484   Not collective
485 
486   Input Parameter:
487 . mesh - The DMPlex
488 
489   Output Parameter:
490 . dim - The topological mesh dimension
491 
492   Level: beginner
493 
494 .seealso: DMPlexCreate()
495 @*/
496 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
497 {
498   DM_Plex *mesh = (DM_Plex*) dm->data;
499 
500   PetscFunctionBegin;
501   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
502   PetscValidPointer(dim, 2);
503   *dim = mesh->dim;
504   PetscFunctionReturn(0);
505 }
506 
507 #undef __FUNCT__
508 #define __FUNCT__ "DMPlexSetDimension"
509 /*@
510   DMPlexSetDimension - Set the topological mesh dimension
511 
512   Collective on mesh
513 
514   Input Parameters:
515 + mesh - The DMPlex
516 - dim - The topological mesh dimension
517 
518   Level: beginner
519 
520 .seealso: DMPlexCreate()
521 @*/
522 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
523 {
524   DM_Plex *mesh = (DM_Plex*) dm->data;
525 
526   PetscFunctionBegin;
527   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
528   PetscValidLogicalCollectiveInt(dm, dim, 2);
529   mesh->dim               = dim;
530   mesh->preallocCenterDim = dim;
531   PetscFunctionReturn(0);
532 }
533 
534 #undef __FUNCT__
535 #define __FUNCT__ "DMPlexGetChart"
536 /*@
537   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
538 
539   Not collective
540 
541   Input Parameter:
542 . mesh - The DMPlex
543 
544   Output Parameters:
545 + pStart - The first mesh point
546 - pEnd   - The upper bound for mesh points
547 
548   Level: beginner
549 
550 .seealso: DMPlexCreate(), DMPlexSetChart()
551 @*/
552 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
553 {
554   DM_Plex       *mesh = (DM_Plex*) dm->data;
555   PetscErrorCode ierr;
556 
557   PetscFunctionBegin;
558   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
559   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
560   PetscFunctionReturn(0);
561 }
562 
563 #undef __FUNCT__
564 #define __FUNCT__ "DMPlexSetChart"
565 /*@
566   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
567 
568   Not collective
569 
570   Input Parameters:
571 + mesh - The DMPlex
572 . pStart - The first mesh point
573 - pEnd   - The upper bound for mesh points
574 
575   Output Parameters:
576 
577   Level: beginner
578 
579 .seealso: DMPlexCreate(), DMPlexGetChart()
580 @*/
581 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
582 {
583   DM_Plex       *mesh = (DM_Plex*) dm->data;
584   PetscErrorCode ierr;
585 
586   PetscFunctionBegin;
587   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
588   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
589   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
590   PetscFunctionReturn(0);
591 }
592 
593 #undef __FUNCT__
594 #define __FUNCT__ "DMPlexGetConeSize"
595 /*@
596   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
597 
598   Not collective
599 
600   Input Parameters:
601 + mesh - The DMPlex
602 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
603 
604   Output Parameter:
605 . size - The cone size for point p
606 
607   Level: beginner
608 
609 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
610 @*/
611 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
612 {
613   DM_Plex       *mesh = (DM_Plex*) dm->data;
614   PetscErrorCode ierr;
615 
616   PetscFunctionBegin;
617   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
618   PetscValidPointer(size, 3);
619   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
620   PetscFunctionReturn(0);
621 }
622 
623 #undef __FUNCT__
624 #define __FUNCT__ "DMPlexSetConeSize"
625 /*@
626   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
627 
628   Not collective
629 
630   Input Parameters:
631 + mesh - The DMPlex
632 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
633 - size - The cone size for point p
634 
635   Output Parameter:
636 
637   Note:
638   This should be called after DMPlexSetChart().
639 
640   Level: beginner
641 
642 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
643 @*/
644 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
645 {
646   DM_Plex       *mesh = (DM_Plex*) dm->data;
647   PetscErrorCode ierr;
648 
649   PetscFunctionBegin;
650   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
651   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
652 
653   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
654   PetscFunctionReturn(0);
655 }
656 
657 #undef __FUNCT__
658 #define __FUNCT__ "DMPlexGetCone"
659 /*@C
660   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
661 
662   Not collective
663 
664   Input Parameters:
665 + mesh - The DMPlex
666 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
667 
668   Output Parameter:
669 . cone - An array of points which are on the in-edges for point p
670 
671   Level: beginner
672 
673   Fortran Notes:
674   Since it returns an array, this routine is only available in Fortran 90, and you must
675   include petsc.h90 in your code.
676 
677   You must also call DMPlexRestoreCone() after you finish using the returned array.
678 
679 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
680 @*/
681 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
682 {
683   DM_Plex       *mesh = (DM_Plex*) dm->data;
684   PetscInt       off;
685   PetscErrorCode ierr;
686 
687   PetscFunctionBegin;
688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
689   PetscValidPointer(cone, 3);
690   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
691   *cone = &mesh->cones[off];
692   PetscFunctionReturn(0);
693 }
694 
695 #undef __FUNCT__
696 #define __FUNCT__ "DMPlexSetCone"
697 /*@
698   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
699 
700   Not collective
701 
702   Input Parameters:
703 + mesh - The DMPlex
704 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
705 - cone - An array of points which are on the in-edges for point p
706 
707   Output Parameter:
708 
709   Note:
710   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
711 
712   Level: beginner
713 
714 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
715 @*/
716 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
717 {
718   DM_Plex       *mesh = (DM_Plex*) dm->data;
719   PetscInt       pStart, pEnd;
720   PetscInt       dof, off, c;
721   PetscErrorCode ierr;
722 
723   PetscFunctionBegin;
724   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
725   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
726   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
727   if (dof) PetscValidPointer(cone, 3);
728   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
729   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);
730   for (c = 0; c < dof; ++c) {
731     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);
732     mesh->cones[off+c] = cone[c];
733   }
734   PetscFunctionReturn(0);
735 }
736 
737 #undef __FUNCT__
738 #define __FUNCT__ "DMPlexGetConeOrientation"
739 /*@C
740   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
741 
742   Not collective
743 
744   Input Parameters:
745 + mesh - The DMPlex
746 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
747 
748   Output Parameter:
749 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
750                     integer giving the prescription for cone traversal. If it is negative, the cone is
751                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
752                     the index of the cone point on which to start.
753 
754   Level: beginner
755 
756   Fortran Notes:
757   Since it returns an array, this routine is only available in Fortran 90, and you must
758   include petsc.h90 in your code.
759 
760   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
761 
762 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
763 @*/
764 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
765 {
766   DM_Plex       *mesh = (DM_Plex*) dm->data;
767   PetscInt       off;
768   PetscErrorCode ierr;
769 
770   PetscFunctionBegin;
771   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
772 #if defined(PETSC_USE_DEBUG)
773   {
774     PetscInt dof;
775     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
776     if (dof) PetscValidPointer(coneOrientation, 3);
777   }
778 #endif
779   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
780 
781   *coneOrientation = &mesh->coneOrientations[off];
782   PetscFunctionReturn(0);
783 }
784 
785 #undef __FUNCT__
786 #define __FUNCT__ "DMPlexSetConeOrientation"
787 /*@
788   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
789 
790   Not collective
791 
792   Input Parameters:
793 + mesh - The DMPlex
794 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
795 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
796                     integer giving the prescription for cone traversal. If it is negative, the cone is
797                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
798                     the index of the cone point on which to start.
799 
800   Output Parameter:
801 
802   Note:
803   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
804 
805   Level: beginner
806 
807 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
808 @*/
809 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
810 {
811   DM_Plex       *mesh = (DM_Plex*) dm->data;
812   PetscInt       pStart, pEnd;
813   PetscInt       dof, off, c;
814   PetscErrorCode ierr;
815 
816   PetscFunctionBegin;
817   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
818   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
819   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
820   if (dof) PetscValidPointer(coneOrientation, 3);
821   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
822   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);
823   for (c = 0; c < dof; ++c) {
824     PetscInt cdof, o = coneOrientation[c];
825 
826     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
827     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);
828     mesh->coneOrientations[off+c] = o;
829   }
830   PetscFunctionReturn(0);
831 }
832 
833 #undef __FUNCT__
834 #define __FUNCT__ "DMPlexInsertCone"
835 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
836 {
837   DM_Plex       *mesh = (DM_Plex*) dm->data;
838   PetscInt       pStart, pEnd;
839   PetscInt       dof, off;
840   PetscErrorCode ierr;
841 
842   PetscFunctionBegin;
843   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
844   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
845   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);
846   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);
847   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
848   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
849   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);
850   mesh->cones[off+conePos] = conePoint;
851   PetscFunctionReturn(0);
852 }
853 
854 #undef __FUNCT__
855 #define __FUNCT__ "DMPlexInsertConeOrientation"
856 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
857 {
858   DM_Plex       *mesh = (DM_Plex*) dm->data;
859   PetscInt       pStart, pEnd;
860   PetscInt       dof, off;
861   PetscErrorCode ierr;
862 
863   PetscFunctionBegin;
864   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
865   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
866   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);
867   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
868   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
869   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);
870   mesh->coneOrientations[off+conePos] = coneOrientation;
871   PetscFunctionReturn(0);
872 }
873 
874 #undef __FUNCT__
875 #define __FUNCT__ "DMPlexGetSupportSize"
876 /*@
877   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
878 
879   Not collective
880 
881   Input Parameters:
882 + mesh - The DMPlex
883 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
884 
885   Output Parameter:
886 . size - The support size for point p
887 
888   Level: beginner
889 
890 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
891 @*/
892 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
893 {
894   DM_Plex       *mesh = (DM_Plex*) dm->data;
895   PetscErrorCode ierr;
896 
897   PetscFunctionBegin;
898   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
899   PetscValidPointer(size, 3);
900   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
901   PetscFunctionReturn(0);
902 }
903 
904 #undef __FUNCT__
905 #define __FUNCT__ "DMPlexSetSupportSize"
906 /*@
907   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
908 
909   Not collective
910 
911   Input Parameters:
912 + mesh - The DMPlex
913 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
914 - size - The support size for point p
915 
916   Output Parameter:
917 
918   Note:
919   This should be called after DMPlexSetChart().
920 
921   Level: beginner
922 
923 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
924 @*/
925 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
926 {
927   DM_Plex       *mesh = (DM_Plex*) dm->data;
928   PetscErrorCode ierr;
929 
930   PetscFunctionBegin;
931   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
932   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
933 
934   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
935   PetscFunctionReturn(0);
936 }
937 
938 #undef __FUNCT__
939 #define __FUNCT__ "DMPlexGetSupport"
940 /*@C
941   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
942 
943   Not collective
944 
945   Input Parameters:
946 + mesh - The DMPlex
947 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
948 
949   Output Parameter:
950 . support - An array of points which are on the out-edges for point p
951 
952   Level: beginner
953 
954   Fortran Notes:
955   Since it returns an array, this routine is only available in Fortran 90, and you must
956   include petsc.h90 in your code.
957 
958   You must also call DMPlexRestoreSupport() after you finish using the returned array.
959 
960 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
961 @*/
962 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
963 {
964   DM_Plex       *mesh = (DM_Plex*) dm->data;
965   PetscInt       off;
966   PetscErrorCode ierr;
967 
968   PetscFunctionBegin;
969   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
970   PetscValidPointer(support, 3);
971   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
972   *support = &mesh->supports[off];
973   PetscFunctionReturn(0);
974 }
975 
976 #undef __FUNCT__
977 #define __FUNCT__ "DMPlexSetSupport"
978 /*@
979   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
980 
981   Not collective
982 
983   Input Parameters:
984 + mesh - The DMPlex
985 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
986 - support - An array of points which are on the in-edges for point p
987 
988   Output Parameter:
989 
990   Note:
991   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
992 
993   Level: beginner
994 
995 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
996 @*/
997 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
998 {
999   DM_Plex       *mesh = (DM_Plex*) dm->data;
1000   PetscInt       pStart, pEnd;
1001   PetscInt       dof, off, c;
1002   PetscErrorCode ierr;
1003 
1004   PetscFunctionBegin;
1005   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1006   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1007   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1008   if (dof) PetscValidPointer(support, 3);
1009   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1010   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);
1011   for (c = 0; c < dof; ++c) {
1012     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);
1013     mesh->supports[off+c] = support[c];
1014   }
1015   PetscFunctionReturn(0);
1016 }
1017 
1018 #undef __FUNCT__
1019 #define __FUNCT__ "DMPlexInsertSupport"
1020 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1021 {
1022   DM_Plex       *mesh = (DM_Plex*) dm->data;
1023   PetscInt       pStart, pEnd;
1024   PetscInt       dof, off;
1025   PetscErrorCode ierr;
1026 
1027   PetscFunctionBegin;
1028   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1029   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1030   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1031   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1032   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);
1033   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);
1034   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);
1035   mesh->supports[off+supportPos] = supportPoint;
1036   PetscFunctionReturn(0);
1037 }
1038 
1039 #undef __FUNCT__
1040 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1041 /*@C
1042   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1043 
1044   Not collective
1045 
1046   Input Parameters:
1047 + mesh - The DMPlex
1048 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1049 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1050 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1051 
1052   Output Parameters:
1053 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1054 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1055 
1056   Note:
1057   If using internal storage (points is NULL on input), each call overwrites the last output.
1058 
1059   Fortran Notes:
1060   Since it returns an array, this routine is only available in Fortran 90, and you must
1061   include petsc.h90 in your code.
1062 
1063   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1064 
1065   Level: beginner
1066 
1067 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1068 @*/
1069 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1070 {
1071   DM_Plex        *mesh = (DM_Plex*) dm->data;
1072   PetscInt       *closure, *fifo;
1073   const PetscInt *tmp = NULL, *tmpO = NULL;
1074   PetscInt        tmpSize, t;
1075   PetscInt        depth       = 0, maxSize;
1076   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1077   PetscErrorCode  ierr;
1078 
1079   PetscFunctionBegin;
1080   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1081   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1082   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1083   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1084   if (*points) {
1085     closure = *points;
1086   } else {
1087     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1088   }
1089   closure[0] = p; closure[1] = 0;
1090   /* This is only 1-level */
1091   if (useCone) {
1092     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1093     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1094     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1095   } else {
1096     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1097     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1098   }
1099   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1100     const PetscInt cp = tmp[t];
1101     const PetscInt co = tmpO ? tmpO[t] : 0;
1102 
1103     closure[closureSize]   = cp;
1104     closure[closureSize+1] = co;
1105     fifo[fifoSize]         = cp;
1106     fifo[fifoSize+1]       = co;
1107   }
1108   while (fifoSize - fifoStart) {
1109     const PetscInt q   = fifo[fifoStart];
1110     const PetscInt o   = fifo[fifoStart+1];
1111     const PetscInt rev = o >= 0 ? 0 : 1;
1112     const PetscInt off = rev ? -(o+1) : o;
1113 
1114     if (useCone) {
1115       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1116       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1117       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1118     } else {
1119       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1120       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1121       tmpO = NULL;
1122     }
1123     for (t = 0; t < tmpSize; ++t) {
1124       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1125       const PetscInt cp = tmp[i];
1126       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1127       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1128        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1129       PetscInt       co = tmpO ? tmpO[i] : 0;
1130       PetscInt       c;
1131 
1132       if (rev) {
1133         PetscInt childSize, coff;
1134         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1135         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1136         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1137       }
1138       /* Check for duplicate */
1139       for (c = 0; c < closureSize; c += 2) {
1140         if (closure[c] == cp) break;
1141       }
1142       if (c == closureSize) {
1143         closure[closureSize]   = cp;
1144         closure[closureSize+1] = co;
1145         fifo[fifoSize]         = cp;
1146         fifo[fifoSize+1]       = co;
1147         closureSize           += 2;
1148         fifoSize              += 2;
1149       }
1150     }
1151     fifoStart += 2;
1152   }
1153   if (numPoints) *numPoints = closureSize/2;
1154   if (points)    *points    = closure;
1155   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1156   PetscFunctionReturn(0);
1157 }
1158 
1159 #undef __FUNCT__
1160 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1161 /*@C
1162   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1163 
1164   Not collective
1165 
1166   Input Parameters:
1167 + mesh - The DMPlex
1168 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1169 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1170 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1171 
1172   Output Parameters:
1173 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1174 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1175 
1176   Note:
1177   If not using internal storage (points is not NULL on input), this call is unnecessary
1178 
1179   Fortran Notes:
1180   Since it returns an array, this routine is only available in Fortran 90, and you must
1181   include petsc.h90 in your code.
1182 
1183   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1184 
1185   Level: beginner
1186 
1187 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1188 @*/
1189 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1190 {
1191   PetscErrorCode ierr;
1192 
1193   PetscFunctionBegin;
1194   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1195   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1196   PetscFunctionReturn(0);
1197 }
1198 
1199 #undef __FUNCT__
1200 #define __FUNCT__ "DMPlexGetMaxSizes"
1201 /*@
1202   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1203 
1204   Not collective
1205 
1206   Input Parameter:
1207 . mesh - The DMPlex
1208 
1209   Output Parameters:
1210 + maxConeSize - The maximum number of in-edges
1211 - maxSupportSize - The maximum number of out-edges
1212 
1213   Level: beginner
1214 
1215 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1216 @*/
1217 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1218 {
1219   DM_Plex *mesh = (DM_Plex*) dm->data;
1220 
1221   PetscFunctionBegin;
1222   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1223   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1224   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1225   PetscFunctionReturn(0);
1226 }
1227 
1228 #undef __FUNCT__
1229 #define __FUNCT__ "DMSetUp_Plex"
1230 PetscErrorCode DMSetUp_Plex(DM dm)
1231 {
1232   DM_Plex       *mesh = (DM_Plex*) dm->data;
1233   PetscInt       size;
1234   PetscErrorCode ierr;
1235 
1236   PetscFunctionBegin;
1237   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1238   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1239   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1240   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1241   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1242   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1243   if (mesh->maxSupportSize) {
1244     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1245     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1246     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1247   }
1248   PetscFunctionReturn(0);
1249 }
1250 
1251 #undef __FUNCT__
1252 #define __FUNCT__ "DMCreateSubDM_Plex"
1253 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1254 {
1255   PetscSection   section, sectionGlobal;
1256   PetscInt      *subIndices;
1257   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1258   PetscErrorCode ierr;
1259 
1260   PetscFunctionBegin;
1261   if (!numFields) PetscFunctionReturn(0);
1262   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1263   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1264   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1265   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1266   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1267   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);
1268   if (is) {
1269     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1270     for (p = pStart; p < pEnd; ++p) {
1271       PetscInt gdof;
1272 
1273       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1274       if (gdof > 0) {
1275         for (f = 0; f < numFields; ++f) {
1276           PetscInt fdof, fcdof;
1277 
1278           ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1279           ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1280           subSize += fdof-fcdof;
1281         }
1282       }
1283     }
1284     ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1285     for (p = pStart; p < pEnd; ++p) {
1286       PetscInt gdof, goff;
1287 
1288       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1289       if (gdof > 0) {
1290         ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1291         for (f = 0; f < numFields; ++f) {
1292           PetscInt fdof, fcdof, fc, f2, poff = 0;
1293 
1294           /* Can get rid of this loop by storing field information in the global section */
1295           for (f2 = 0; f2 < fields[f]; ++f2) {
1296             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1297             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1298             poff += fdof-fcdof;
1299           }
1300           ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1301           ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1302           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1303             subIndices[subOff] = goff+poff+fc;
1304           }
1305         }
1306       }
1307     }
1308     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
1309   }
1310   if (subdm) {
1311     PetscSection subsection;
1312     PetscBool    haveNull = PETSC_FALSE;
1313     PetscInt     f, nf = 0;
1314 
1315     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1316     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1317     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1318     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1319     for (f = 0; f < numFields; ++f) {
1320       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1321       if ((*subdm)->nullspaceConstructors[f]) {
1322         haveNull = PETSC_TRUE;
1323         nf       = f;
1324       }
1325     }
1326     if (haveNull) {
1327       MatNullSpace nullSpace;
1328 
1329       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1330       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1331       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1332     }
1333     if (dm->fields) {
1334       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);
1335       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1336       for (f = 0; f < numFields; ++f) {
1337         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1338       }
1339       if (numFields == 1) {
1340         MatNullSpace space;
1341         Mat          pmat;
1342 
1343         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1344         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1345         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1346         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1347         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1348         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1349       }
1350     }
1351   }
1352   PetscFunctionReturn(0);
1353 }
1354 
1355 #undef __FUNCT__
1356 #define __FUNCT__ "DMPlexSymmetrize"
1357 /*@
1358   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1359 
1360   Not collective
1361 
1362   Input Parameter:
1363 . mesh - The DMPlex
1364 
1365   Output Parameter:
1366 
1367   Note:
1368   This should be called after all calls to DMPlexSetCone()
1369 
1370   Level: beginner
1371 
1372 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1373 @*/
1374 PetscErrorCode DMPlexSymmetrize(DM dm)
1375 {
1376   DM_Plex       *mesh = (DM_Plex*) dm->data;
1377   PetscInt      *offsets;
1378   PetscInt       supportSize;
1379   PetscInt       pStart, pEnd, p;
1380   PetscErrorCode ierr;
1381 
1382   PetscFunctionBegin;
1383   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1384   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1385   /* Calculate support sizes */
1386   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1387   for (p = pStart; p < pEnd; ++p) {
1388     PetscInt dof, off, c;
1389 
1390     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1391     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1392     for (c = off; c < off+dof; ++c) {
1393       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1394     }
1395   }
1396   for (p = pStart; p < pEnd; ++p) {
1397     PetscInt dof;
1398 
1399     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1400 
1401     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1402   }
1403   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1404   /* Calculate supports */
1405   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1406   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1407   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1408   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1409   for (p = pStart; p < pEnd; ++p) {
1410     PetscInt dof, off, c;
1411 
1412     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1413     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1414     for (c = off; c < off+dof; ++c) {
1415       const PetscInt q = mesh->cones[c];
1416       PetscInt       offS;
1417 
1418       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1419 
1420       mesh->supports[offS+offsets[q]] = p;
1421       ++offsets[q];
1422     }
1423   }
1424   ierr = PetscFree(offsets);CHKERRQ(ierr);
1425   PetscFunctionReturn(0);
1426 }
1427 
1428 #undef __FUNCT__
1429 #define __FUNCT__ "DMPlexSetDepth_Private"
1430 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1431 {
1432   PetscInt       d;
1433   PetscErrorCode ierr;
1434 
1435   PetscFunctionBegin;
1436   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1437   if (d < 0) {
1438     /* We are guaranteed that the point has a cone since the depth was not yet set */
1439     const PetscInt *cone = NULL;
1440     PetscInt        dCone;
1441 
1442     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1443     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1444     d    = dCone+1;
1445     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1446   }
1447   *depth = d;
1448   PetscFunctionReturn(0);
1449 }
1450 
1451 #undef __FUNCT__
1452 #define __FUNCT__ "DMPlexStratify"
1453 /*@
1454   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1455   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1456   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1457   the DAG.
1458 
1459   Not collective
1460 
1461   Input Parameter:
1462 . mesh - The DMPlex
1463 
1464   Output Parameter:
1465 
1466   Notes:
1467   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1468   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1469 
1470   This should be called after all calls to DMPlexSymmetrize()
1471 
1472   Level: beginner
1473 
1474 .seealso: DMPlexCreate(), DMPlexSymmetrize()
1475 @*/
1476 PetscErrorCode DMPlexStratify(DM dm)
1477 {
1478   DM_Plex       *mesh = (DM_Plex*) dm->data;
1479   PetscInt       pStart, pEnd, p;
1480   PetscInt       numRoots = 0, numLeaves = 0;
1481   PetscErrorCode ierr;
1482 
1483   PetscFunctionBegin;
1484   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1485   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1486   /* Calculate depth */
1487   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1488   /* Initialize roots and count leaves */
1489   for (p = pStart; p < pEnd; ++p) {
1490     PetscInt coneSize, supportSize;
1491 
1492     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1493     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1494     if (!coneSize && supportSize) {
1495       ++numRoots;
1496       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
1497     } else if (!supportSize && coneSize) {
1498       ++numLeaves;
1499     } else if (!supportSize && !coneSize) {
1500       /* Isolated points */
1501       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
1502     }
1503   }
1504   if (numRoots + numLeaves == (pEnd - pStart)) {
1505     for (p = pStart; p < pEnd; ++p) {
1506       PetscInt coneSize, supportSize;
1507 
1508       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1509       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1510       if (!supportSize && coneSize) {
1511         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
1512       }
1513     }
1514   } else {
1515     /* This might be slow since lookup is not fast */
1516     for (p = pStart; p < pEnd; ++p) {
1517       PetscInt depth;
1518 
1519       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
1520     }
1521   }
1522   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1523   PetscFunctionReturn(0);
1524 }
1525 
1526 #undef __FUNCT__
1527 #define __FUNCT__ "DMPlexGetJoin"
1528 /*@C
1529   DMPlexGetJoin - Get an array for the join of the set of points
1530 
1531   Not Collective
1532 
1533   Input Parameters:
1534 + dm - The DMPlex object
1535 . numPoints - The number of input points for the join
1536 - points - The input points
1537 
1538   Output Parameters:
1539 + numCoveredPoints - The number of points in the join
1540 - coveredPoints - The points in the join
1541 
1542   Level: intermediate
1543 
1544   Note: Currently, this is restricted to a single level join
1545 
1546   Fortran Notes:
1547   Since it returns an array, this routine is only available in Fortran 90, and you must
1548   include petsc.h90 in your code.
1549 
1550   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1551 
1552 .keywords: mesh
1553 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1554 @*/
1555 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1556 {
1557   DM_Plex       *mesh = (DM_Plex*) dm->data;
1558   PetscInt      *join[2];
1559   PetscInt       joinSize, i = 0;
1560   PetscInt       dof, off, p, c, m;
1561   PetscErrorCode ierr;
1562 
1563   PetscFunctionBegin;
1564   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1565   PetscValidPointer(points, 2);
1566   PetscValidPointer(numCoveredPoints, 3);
1567   PetscValidPointer(coveredPoints, 4);
1568   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1569   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1570   /* Copy in support of first point */
1571   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
1572   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
1573   for (joinSize = 0; joinSize < dof; ++joinSize) {
1574     join[i][joinSize] = mesh->supports[off+joinSize];
1575   }
1576   /* Check each successive support */
1577   for (p = 1; p < numPoints; ++p) {
1578     PetscInt newJoinSize = 0;
1579 
1580     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
1581     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
1582     for (c = 0; c < dof; ++c) {
1583       const PetscInt point = mesh->supports[off+c];
1584 
1585       for (m = 0; m < joinSize; ++m) {
1586         if (point == join[i][m]) {
1587           join[1-i][newJoinSize++] = point;
1588           break;
1589         }
1590       }
1591     }
1592     joinSize = newJoinSize;
1593     i        = 1-i;
1594   }
1595   *numCoveredPoints = joinSize;
1596   *coveredPoints    = join[i];
1597   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1598   PetscFunctionReturn(0);
1599 }
1600 
1601 #undef __FUNCT__
1602 #define __FUNCT__ "DMPlexRestoreJoin"
1603 /*@C
1604   DMPlexRestoreJoin - Restore an array for the join of the set of points
1605 
1606   Not Collective
1607 
1608   Input Parameters:
1609 + dm - The DMPlex object
1610 . numPoints - The number of input points for the join
1611 - points - The input points
1612 
1613   Output Parameters:
1614 + numCoveredPoints - The number of points in the join
1615 - coveredPoints - The points in the join
1616 
1617   Fortran Notes:
1618   Since it returns an array, this routine is only available in Fortran 90, and you must
1619   include petsc.h90 in your code.
1620 
1621   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1622 
1623   Level: intermediate
1624 
1625 .keywords: mesh
1626 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
1627 @*/
1628 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1629 {
1630   PetscErrorCode ierr;
1631 
1632   PetscFunctionBegin;
1633   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1634   PetscValidPointer(coveredPoints, 4);
1635   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1636   PetscFunctionReturn(0);
1637 }
1638 
1639 #undef __FUNCT__
1640 #define __FUNCT__ "DMPlexGetFullJoin"
1641 /*@C
1642   DMPlexGetFullJoin - Get an array for the join of the set of points
1643 
1644   Not Collective
1645 
1646   Input Parameters:
1647 + dm - The DMPlex object
1648 . numPoints - The number of input points for the join
1649 - points - The input points
1650 
1651   Output Parameters:
1652 + numCoveredPoints - The number of points in the join
1653 - coveredPoints - The points in the join
1654 
1655   Fortran Notes:
1656   Since it returns an array, this routine is only available in Fortran 90, and you must
1657   include petsc.h90 in your code.
1658 
1659   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1660 
1661   Level: intermediate
1662 
1663 .keywords: mesh
1664 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
1665 @*/
1666 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1667 {
1668   DM_Plex       *mesh = (DM_Plex*) dm->data;
1669   PetscInt      *offsets, **closures;
1670   PetscInt      *join[2];
1671   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
1672   PetscInt       p, d, c, m;
1673   PetscErrorCode ierr;
1674 
1675   PetscFunctionBegin;
1676   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1677   PetscValidPointer(points, 2);
1678   PetscValidPointer(numCoveredPoints, 3);
1679   PetscValidPointer(coveredPoints, 4);
1680 
1681   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1682   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1683   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
1684   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1685   maxSize = PetscPowInt(mesh->maxSupportSize,depth+1);
1686   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1687   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1688 
1689   for (p = 0; p < numPoints; ++p) {
1690     PetscInt closureSize;
1691 
1692     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
1693 
1694     offsets[p*(depth+2)+0] = 0;
1695     for (d = 0; d < depth+1; ++d) {
1696       PetscInt pStart, pEnd, i;
1697 
1698       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1699       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
1700         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1701           offsets[p*(depth+2)+d+1] = i;
1702           break;
1703         }
1704       }
1705       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
1706     }
1707     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);
1708   }
1709   for (d = 0; d < depth+1; ++d) {
1710     PetscInt dof;
1711 
1712     /* Copy in support of first point */
1713     dof = offsets[d+1] - offsets[d];
1714     for (joinSize = 0; joinSize < dof; ++joinSize) {
1715       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
1716     }
1717     /* Check each successive cone */
1718     for (p = 1; p < numPoints && joinSize; ++p) {
1719       PetscInt newJoinSize = 0;
1720 
1721       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
1722       for (c = 0; c < dof; ++c) {
1723         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
1724 
1725         for (m = 0; m < joinSize; ++m) {
1726           if (point == join[i][m]) {
1727             join[1-i][newJoinSize++] = point;
1728             break;
1729           }
1730         }
1731       }
1732       joinSize = newJoinSize;
1733       i        = 1-i;
1734     }
1735     if (joinSize) break;
1736   }
1737   *numCoveredPoints = joinSize;
1738   *coveredPoints    = join[i];
1739   for (p = 0; p < numPoints; ++p) {
1740     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
1741   }
1742   ierr = PetscFree(closures);CHKERRQ(ierr);
1743   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1744   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1745   PetscFunctionReturn(0);
1746 }
1747 
1748 #undef __FUNCT__
1749 #define __FUNCT__ "DMPlexGetMeet"
1750 /*@C
1751   DMPlexGetMeet - Get an array for the meet of the set of points
1752 
1753   Not Collective
1754 
1755   Input Parameters:
1756 + dm - The DMPlex object
1757 . numPoints - The number of input points for the meet
1758 - points - The input points
1759 
1760   Output Parameters:
1761 + numCoveredPoints - The number of points in the meet
1762 - coveredPoints - The points in the meet
1763 
1764   Level: intermediate
1765 
1766   Note: Currently, this is restricted to a single level meet
1767 
1768   Fortran Notes:
1769   Since it returns an array, this routine is only available in Fortran 90, and you must
1770   include petsc.h90 in your code.
1771 
1772   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1773 
1774 .keywords: mesh
1775 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
1776 @*/
1777 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
1778 {
1779   DM_Plex       *mesh = (DM_Plex*) dm->data;
1780   PetscInt      *meet[2];
1781   PetscInt       meetSize, i = 0;
1782   PetscInt       dof, off, p, c, m;
1783   PetscErrorCode ierr;
1784 
1785   PetscFunctionBegin;
1786   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1787   PetscValidPointer(points, 2);
1788   PetscValidPointer(numCoveringPoints, 3);
1789   PetscValidPointer(coveringPoints, 4);
1790   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1791   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1792   /* Copy in cone of first point */
1793   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
1794   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
1795   for (meetSize = 0; meetSize < dof; ++meetSize) {
1796     meet[i][meetSize] = mesh->cones[off+meetSize];
1797   }
1798   /* Check each successive cone */
1799   for (p = 1; p < numPoints; ++p) {
1800     PetscInt newMeetSize = 0;
1801 
1802     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
1803     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
1804     for (c = 0; c < dof; ++c) {
1805       const PetscInt point = mesh->cones[off+c];
1806 
1807       for (m = 0; m < meetSize; ++m) {
1808         if (point == meet[i][m]) {
1809           meet[1-i][newMeetSize++] = point;
1810           break;
1811         }
1812       }
1813     }
1814     meetSize = newMeetSize;
1815     i        = 1-i;
1816   }
1817   *numCoveringPoints = meetSize;
1818   *coveringPoints    = meet[i];
1819   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1820   PetscFunctionReturn(0);
1821 }
1822 
1823 #undef __FUNCT__
1824 #define __FUNCT__ "DMPlexRestoreMeet"
1825 /*@C
1826   DMPlexRestoreMeet - Restore an array for the meet of the set of points
1827 
1828   Not Collective
1829 
1830   Input Parameters:
1831 + dm - The DMPlex object
1832 . numPoints - The number of input points for the meet
1833 - points - The input points
1834 
1835   Output Parameters:
1836 + numCoveredPoints - The number of points in the meet
1837 - coveredPoints - The points in the meet
1838 
1839   Level: intermediate
1840 
1841   Fortran Notes:
1842   Since it returns an array, this routine is only available in Fortran 90, and you must
1843   include petsc.h90 in your code.
1844 
1845   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1846 
1847 .keywords: mesh
1848 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
1849 @*/
1850 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1851 {
1852   PetscErrorCode ierr;
1853 
1854   PetscFunctionBegin;
1855   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1856   PetscValidPointer(coveredPoints, 4);
1857   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1858   PetscFunctionReturn(0);
1859 }
1860 
1861 #undef __FUNCT__
1862 #define __FUNCT__ "DMPlexGetFullMeet"
1863 /*@C
1864   DMPlexGetFullMeet - Get an array for the meet of the set of points
1865 
1866   Not Collective
1867 
1868   Input Parameters:
1869 + dm - The DMPlex object
1870 . numPoints - The number of input points for the meet
1871 - points - The input points
1872 
1873   Output Parameters:
1874 + numCoveredPoints - The number of points in the meet
1875 - coveredPoints - The points in the meet
1876 
1877   Level: intermediate
1878 
1879   Fortran Notes:
1880   Since it returns an array, this routine is only available in Fortran 90, and you must
1881   include petsc.h90 in your code.
1882 
1883   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1884 
1885 .keywords: mesh
1886 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
1887 @*/
1888 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1889 {
1890   DM_Plex       *mesh = (DM_Plex*) dm->data;
1891   PetscInt      *offsets, **closures;
1892   PetscInt      *meet[2];
1893   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
1894   PetscInt       p, h, c, m;
1895   PetscErrorCode ierr;
1896 
1897   PetscFunctionBegin;
1898   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1899   PetscValidPointer(points, 2);
1900   PetscValidPointer(numCoveredPoints, 3);
1901   PetscValidPointer(coveredPoints, 4);
1902 
1903   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
1904   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1905   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1906   maxSize = PetscPowInt(mesh->maxConeSize,height+1);
1907   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1908   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1909 
1910   for (p = 0; p < numPoints; ++p) {
1911     PetscInt closureSize;
1912 
1913     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
1914 
1915     offsets[p*(height+2)+0] = 0;
1916     for (h = 0; h < height+1; ++h) {
1917       PetscInt pStart, pEnd, i;
1918 
1919       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
1920       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
1921         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1922           offsets[p*(height+2)+h+1] = i;
1923           break;
1924         }
1925       }
1926       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
1927     }
1928     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);
1929   }
1930   for (h = 0; h < height+1; ++h) {
1931     PetscInt dof;
1932 
1933     /* Copy in cone of first point */
1934     dof = offsets[h+1] - offsets[h];
1935     for (meetSize = 0; meetSize < dof; ++meetSize) {
1936       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
1937     }
1938     /* Check each successive cone */
1939     for (p = 1; p < numPoints && meetSize; ++p) {
1940       PetscInt newMeetSize = 0;
1941 
1942       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
1943       for (c = 0; c < dof; ++c) {
1944         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
1945 
1946         for (m = 0; m < meetSize; ++m) {
1947           if (point == meet[i][m]) {
1948             meet[1-i][newMeetSize++] = point;
1949             break;
1950           }
1951         }
1952       }
1953       meetSize = newMeetSize;
1954       i        = 1-i;
1955     }
1956     if (meetSize) break;
1957   }
1958   *numCoveredPoints = meetSize;
1959   *coveredPoints    = meet[i];
1960   for (p = 0; p < numPoints; ++p) {
1961     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
1962   }
1963   ierr = PetscFree(closures);CHKERRQ(ierr);
1964   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1965   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1966   PetscFunctionReturn(0);
1967 }
1968 
1969 #undef __FUNCT__
1970 #define __FUNCT__ "DMPlexGetNumFaceVertices"
1971 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
1972 {
1973   MPI_Comm       comm;
1974   PetscErrorCode ierr;
1975 
1976   PetscFunctionBegin;
1977   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1978   PetscValidPointer(numFaceVertices,3);
1979   switch (cellDim) {
1980   case 0:
1981     *numFaceVertices = 0;
1982     break;
1983   case 1:
1984     *numFaceVertices = 1;
1985     break;
1986   case 2:
1987     switch (numCorners) {
1988     case 3: /* triangle */
1989       *numFaceVertices = 2; /* Edge has 2 vertices */
1990       break;
1991     case 4: /* quadrilateral */
1992       *numFaceVertices = 2; /* Edge has 2 vertices */
1993       break;
1994     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
1995       *numFaceVertices = 3; /* Edge has 3 vertices */
1996       break;
1997     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
1998       *numFaceVertices = 3; /* Edge has 3 vertices */
1999       break;
2000     default:
2001       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2002     }
2003     break;
2004   case 3:
2005     switch (numCorners) {
2006     case 4: /* tetradehdron */
2007       *numFaceVertices = 3; /* Face has 3 vertices */
2008       break;
2009     case 6: /* tet cohesive cells */
2010       *numFaceVertices = 4; /* Face has 4 vertices */
2011       break;
2012     case 8: /* hexahedron */
2013       *numFaceVertices = 4; /* Face has 4 vertices */
2014       break;
2015     case 9: /* tet cohesive Lagrange cells */
2016       *numFaceVertices = 6; /* Face has 6 vertices */
2017       break;
2018     case 10: /* quadratic tetrahedron */
2019       *numFaceVertices = 6; /* Face has 6 vertices */
2020       break;
2021     case 12: /* hex cohesive Lagrange cells */
2022       *numFaceVertices = 6; /* Face has 6 vertices */
2023       break;
2024     case 18: /* quadratic tet cohesive Lagrange cells */
2025       *numFaceVertices = 6; /* Face has 6 vertices */
2026       break;
2027     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2028       *numFaceVertices = 9; /* Face has 9 vertices */
2029       break;
2030     default:
2031       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2032     }
2033     break;
2034   default:
2035     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2036   }
2037   PetscFunctionReturn(0);
2038 }
2039 
2040 #undef __FUNCT__
2041 #define __FUNCT__ "DMPlexOrient"
2042 /* Trys to give the mesh a consistent orientation */
2043 PetscErrorCode DMPlexOrient(DM dm)
2044 {
2045   PetscBT        seenCells, flippedCells, seenFaces;
2046   PetscInt      *faceFIFO, fTop, fBottom;
2047   PetscInt       dim, h, cStart, cEnd, c, fStart, fEnd, face, maxConeSize, *revcone, *revconeO;
2048   PetscErrorCode ierr;
2049 
2050   PetscFunctionBegin;
2051   /* Truth Table
2052      mismatch    flips   do action   mismatch   flipA ^ flipB   action
2053          F       0 flips     no         F             F           F
2054          F       1 flip      yes        F             T           T
2055          F       2 flips     no         T             F           T
2056          T       0 flips     yes        T             T           F
2057          T       1 flip      no
2058          T       2 flips     yes
2059   */
2060   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2061   ierr = DMPlexGetVTKCellHeight(dm, &h);CHKERRQ(ierr);
2062   ierr = DMPlexGetHeightStratum(dm, h,   &cStart, &cEnd);CHKERRQ(ierr);
2063   ierr = DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);CHKERRQ(ierr);
2064   ierr = PetscBTCreate(cEnd - cStart, &seenCells);CHKERRQ(ierr);
2065   ierr = PetscBTMemzero(cEnd - cStart, seenCells);CHKERRQ(ierr);
2066   ierr = PetscBTCreate(cEnd - cStart, &flippedCells);CHKERRQ(ierr);
2067   ierr = PetscBTMemzero(cEnd - cStart, flippedCells);CHKERRQ(ierr);
2068   ierr = PetscBTCreate(fEnd - fStart, &seenFaces);CHKERRQ(ierr);
2069   ierr = PetscBTMemzero(fEnd - fStart, seenFaces);CHKERRQ(ierr);
2070   ierr = PetscMalloc((fEnd - fStart) * sizeof(PetscInt), &faceFIFO);CHKERRQ(ierr);
2071   fTop = fBottom = 0;
2072   /* Initialize FIFO with first cell */
2073   {
2074     const PetscInt *cone;
2075     PetscInt        coneSize;
2076 
2077     ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
2078     ierr = DMPlexGetCone(dm, cStart, &cone);CHKERRQ(ierr);
2079     for (c = 0; c < coneSize; ++c) {
2080       faceFIFO[fBottom++] = cone[c];
2081       ierr = PetscBTSet(seenFaces, cone[c]-fStart);CHKERRQ(ierr);
2082     }
2083   }
2084   /* Consider each face in FIFO */
2085   while (fTop < fBottom) {
2086     const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
2087     PetscInt        supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
2088     PetscInt        seenA, flippedA, seenB, flippedB, mismatch;
2089 
2090     face = faceFIFO[fTop++];
2091     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
2092     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
2093     if (supportSize < 2) continue;
2094     if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize);
2095     seenA    = PetscBTLookup(seenCells,    support[0]-cStart);
2096     flippedA = PetscBTLookup(flippedCells, support[0]-cStart);
2097     seenB    = PetscBTLookup(seenCells,    support[1]-cStart);
2098     flippedB = PetscBTLookup(flippedCells, support[1]-cStart);
2099 
2100     ierr = DMPlexGetConeSize(dm, support[0], &coneSizeA);CHKERRQ(ierr);
2101     ierr = DMPlexGetConeSize(dm, support[1], &coneSizeB);CHKERRQ(ierr);
2102     ierr = DMPlexGetCone(dm, support[0], &coneA);CHKERRQ(ierr);
2103     ierr = DMPlexGetCone(dm, support[1], &coneB);CHKERRQ(ierr);
2104     ierr = DMPlexGetConeOrientation(dm, support[0], &coneOA);CHKERRQ(ierr);
2105     ierr = DMPlexGetConeOrientation(dm, support[1], &coneOB);CHKERRQ(ierr);
2106     for (c = 0; c < coneSizeA; ++c) {
2107       if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) {
2108         faceFIFO[fBottom++] = coneA[c];
2109         ierr = PetscBTSet(seenFaces, coneA[c]-fStart);CHKERRQ(ierr);
2110       }
2111       if (coneA[c] == face) posA = c;
2112       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2113     }
2114     if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]);
2115     for (c = 0; c < coneSizeB; ++c) {
2116       if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) {
2117         faceFIFO[fBottom++] = coneB[c];
2118         ierr = PetscBTSet(seenFaces, coneB[c]-fStart);CHKERRQ(ierr);
2119       }
2120       if (coneB[c] == face) posB = c;
2121       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2122     }
2123     if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]);
2124 
2125     if (dim == 1) {
2126       mismatch = posA == posB;
2127     } else {
2128       mismatch = coneOA[posA] == coneOB[posB];
2129     }
2130 
2131     if (mismatch ^ (flippedA ^ flippedB)) {
2132       if (seenA && seenB) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen cells %d and %d do not match: Fault mesh is non-orientable", support[0], support[1]);
2133       if (!seenA && !flippedA) {
2134         ierr = PetscBTSet(flippedCells, support[0]-cStart);CHKERRQ(ierr);
2135       } else if (!seenB && !flippedB) {
2136         ierr = PetscBTSet(flippedCells, support[1]-cStart);CHKERRQ(ierr);
2137       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2138     } else if (flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2139     ierr = PetscBTSet(seenCells, support[0]-cStart);CHKERRQ(ierr);
2140     ierr = PetscBTSet(seenCells, support[1]-cStart);CHKERRQ(ierr);
2141   }
2142 
2143   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, NULL);CHKERRQ(ierr);
2144   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2145   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2146   for (c = cStart; c < cEnd; ++c) {
2147     const PetscInt *cone, *coneO;
2148     PetscInt        coneSize, faceSize, cp;
2149 
2150     if (!PetscBTLookup(flippedCells, c-cStart)) continue;
2151     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
2152     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2153     ierr = DMPlexGetConeOrientation(dm, c, &coneO);CHKERRQ(ierr);
2154     for (cp = 0; cp < coneSize; ++cp) {
2155       const PetscInt rcp = coneSize-cp-1;
2156 
2157       ierr = DMPlexGetConeSize(dm, cone[rcp], &faceSize);CHKERRQ(ierr);
2158       revcone[cp]  = cone[rcp];
2159       revconeO[cp] = coneO[rcp] >= 0 ? -(faceSize-coneO[rcp]) : faceSize+coneO[rcp];
2160     }
2161     ierr = DMPlexSetCone(dm, c, revcone);CHKERRQ(ierr);
2162     ierr = DMPlexSetConeOrientation(dm, c, revconeO);CHKERRQ(ierr);
2163   }
2164   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2165   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2166   ierr = PetscBTDestroy(&seenCells);CHKERRQ(ierr);
2167   ierr = PetscBTDestroy(&flippedCells);CHKERRQ(ierr);
2168   ierr = PetscBTDestroy(&seenFaces);CHKERRQ(ierr);
2169   ierr = PetscFree(faceFIFO);CHKERRQ(ierr);
2170   PetscFunctionReturn(0);
2171 }
2172 
2173 #undef __FUNCT__
2174 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Internal"
2175 static PetscErrorCode DMPlexGetAdjacencySingleLevel_Internal(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
2176 {
2177   const PetscInt *support = NULL;
2178   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
2179   PetscErrorCode  ierr;
2180 
2181   PetscFunctionBegin;
2182   if (useClosure) {
2183     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
2184     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
2185     for (s = 0; s < supportSize; ++s) {
2186       const PetscInt *cone = NULL;
2187       PetscInt        coneSize, c, q;
2188 
2189       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2190       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
2191       for (c = 0; c < coneSize; ++c) {
2192         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2193           if (cone[c] == adj[q]) break;
2194         }
2195         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2196       }
2197     }
2198   } else {
2199     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2200     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
2201     for (s = 0; s < supportSize; ++s) {
2202       const PetscInt *cone = NULL;
2203       PetscInt        coneSize, c, q;
2204 
2205       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2206       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2207       for (c = 0; c < coneSize; ++c) {
2208         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2209           if (cone[c] == adj[q]) break;
2210         }
2211         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2212       }
2213     }
2214   }
2215   *adjSize = numAdj;
2216   PetscFunctionReturn(0);
2217 }
2218 
2219 #undef __FUNCT__
2220 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2221 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2222 {
2223   const PetscInt maxFaceCases = 30;
2224   PetscInt       numFaceCases = 0;
2225   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2226   PetscInt      *off, *adj;
2227   PetscInt      *neighborCells, *tmpClosure;
2228   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2229   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2230   PetscErrorCode ierr;
2231 
2232   PetscFunctionBegin;
2233   /* For parallel partitioning, I think you have to communicate supports */
2234   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2235   cellDim = dim - cellHeight;
2236   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2237   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2238   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2239   if (cEnd - cStart == 0) {
2240     if (numVertices) *numVertices = 0;
2241     if (offsets)   *offsets   = NULL;
2242     if (adjacency) *adjacency = NULL;
2243     PetscFunctionReturn(0);
2244   }
2245   numCells  = cEnd - cStart;
2246   faceDepth = depth - cellHeight;
2247   /* Setup face recognition */
2248   if (faceDepth == 1) {
2249     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 */
2250 
2251     for (c = cStart; c < cEnd; ++c) {
2252       PetscInt corners;
2253 
2254       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2255       if (!cornersSeen[corners]) {
2256         PetscInt nFV;
2257 
2258         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2259         cornersSeen[corners] = 1;
2260 
2261         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2262 
2263         numFaceVertices[numFaceCases++] = nFV;
2264       }
2265     }
2266   }
2267   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth+1),PetscPowInt(maxSupportSize,depth+1));
2268   maxNeighbors = PetscPowInt(maxConeSize,depth+1)*PetscPowInt(maxSupportSize,depth+1);
2269   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2270   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2271   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2272   /* Count neighboring cells */
2273   for (cell = cStart; cell < cEnd; ++cell) {
2274     PetscInt numNeighbors = maxNeighbors, n;
2275 
2276     ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2277     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2278     for (n = 0; n < numNeighbors; ++n) {
2279       PetscInt        cellPair[2];
2280       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2281       PetscInt        meetSize = 0;
2282       const PetscInt *meet    = NULL;
2283 
2284       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2285       if (cellPair[0] == cellPair[1]) continue;
2286       if (!found) {
2287         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2288         if (meetSize) {
2289           PetscInt f;
2290 
2291           for (f = 0; f < numFaceCases; ++f) {
2292             if (numFaceVertices[f] == meetSize) {
2293               found = PETSC_TRUE;
2294               break;
2295             }
2296           }
2297         }
2298         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2299       }
2300       if (found) ++off[cell-cStart+1];
2301     }
2302   }
2303   /* Prefix sum */
2304   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2305 
2306   if (adjacency) {
2307     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2308     /* Get neighboring cells */
2309     for (cell = cStart; cell < cEnd; ++cell) {
2310       PetscInt numNeighbors = maxNeighbors, n;
2311       PetscInt cellOffset   = 0;
2312 
2313       ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2314       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2315       for (n = 0; n < numNeighbors; ++n) {
2316         PetscInt        cellPair[2];
2317         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2318         PetscInt        meetSize = 0;
2319         const PetscInt *meet    = NULL;
2320 
2321         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2322         if (cellPair[0] == cellPair[1]) continue;
2323         if (!found) {
2324           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2325           if (meetSize) {
2326             PetscInt f;
2327 
2328             for (f = 0; f < numFaceCases; ++f) {
2329               if (numFaceVertices[f] == meetSize) {
2330                 found = PETSC_TRUE;
2331                 break;
2332               }
2333             }
2334           }
2335           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2336         }
2337         if (found) {
2338           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2339           ++cellOffset;
2340         }
2341       }
2342     }
2343   }
2344   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2345   if (numVertices) *numVertices = numCells;
2346   if (offsets)   *offsets   = off;
2347   if (adjacency) *adjacency = adj;
2348   PetscFunctionReturn(0);
2349 }
2350 
2351 #if defined(PETSC_HAVE_CHACO)
2352 #if defined(PETSC_HAVE_UNISTD_H)
2353 #include <unistd.h>
2354 #endif
2355 /* Chaco does not have an include file */
2356 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2357                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2358                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2359                        int mesh_dims[3], double *goal, int global_method, int local_method,
2360                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2361 
2362 extern int FREE_GRAPH;
2363 
2364 #undef __FUNCT__
2365 #define __FUNCT__ "DMPlexPartition_Chaco"
2366 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2367 {
2368   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2369   MPI_Comm       comm;
2370   int            nvtxs          = numVertices; /* number of vertices in full graph */
2371   int           *vwgts          = NULL;   /* weights for all vertices */
2372   float         *ewgts          = NULL;   /* weights for all edges */
2373   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2374   char          *outassignname  = NULL;   /*  name of assignment output file */
2375   char          *outfilename    = NULL;   /* output file name */
2376   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2377   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2378   int            mesh_dims[3];            /* dimensions of mesh of processors */
2379   double        *goal          = NULL;    /* desired set sizes for each set */
2380   int            global_method = 1;       /* global partitioning algorithm */
2381   int            local_method  = 1;       /* local partitioning algorithm */
2382   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2383   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2384   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2385   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2386   long           seed          = 123636512; /* for random graph mutations */
2387   short int     *assignment;              /* Output partition */
2388   int            fd_stdout, fd_pipe[2];
2389   PetscInt      *points;
2390   PetscMPIInt    commSize;
2391   int            i, v, p;
2392   PetscErrorCode ierr;
2393 
2394   PetscFunctionBegin;
2395   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2396   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2397   if (!numVertices) {
2398     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2399     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2400     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2401     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2402     PetscFunctionReturn(0);
2403   }
2404   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2405   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2406 
2407   if (global_method == INERTIAL_METHOD) {
2408     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2409     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2410   }
2411   mesh_dims[0] = commSize;
2412   mesh_dims[1] = 1;
2413   mesh_dims[2] = 1;
2414   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2415   /* Chaco outputs to stdout. We redirect this to a buffer. */
2416   /* TODO: check error codes for UNIX calls */
2417 #if defined(PETSC_HAVE_UNISTD_H)
2418   {
2419     int piperet;
2420     piperet = pipe(fd_pipe);
2421     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2422     fd_stdout = dup(1);
2423     close(1);
2424     dup2(fd_pipe[1], 1);
2425   }
2426 #endif
2427   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2428                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2429                    vmax, ndims, eigtol, seed);
2430 #if defined(PETSC_HAVE_UNISTD_H)
2431   {
2432     char msgLog[10000];
2433     int  count;
2434 
2435     fflush(stdout);
2436     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2437     if (count < 0) count = 0;
2438     msgLog[count] = 0;
2439     close(1);
2440     dup2(fd_stdout, 1);
2441     close(fd_stdout);
2442     close(fd_pipe[0]);
2443     close(fd_pipe[1]);
2444     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2445   }
2446 #endif
2447   /* Convert to PetscSection+IS */
2448   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2449   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2450   for (v = 0; v < nvtxs; ++v) {
2451     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2452   }
2453   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2454   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2455   for (p = 0, i = 0; p < commSize; ++p) {
2456     for (v = 0; v < nvtxs; ++v) {
2457       if (assignment[v] == p) points[i++] = v;
2458     }
2459   }
2460   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2461   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2462   if (global_method == INERTIAL_METHOD) {
2463     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2464   }
2465   ierr = PetscFree(assignment);CHKERRQ(ierr);
2466   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2467   PetscFunctionReturn(0);
2468 }
2469 #endif
2470 
2471 #if defined(PETSC_HAVE_PARMETIS)
2472 #undef __FUNCT__
2473 #define __FUNCT__ "DMPlexPartition_ParMetis"
2474 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2475 {
2476   PetscFunctionBegin;
2477   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2478   PetscFunctionReturn(0);
2479 }
2480 #endif
2481 
2482 #undef __FUNCT__
2483 #define __FUNCT__ "DMPlexEnlargePartition"
2484 /* Expand the partition by BFS on the adjacency graph */
2485 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2486 {
2487   PetscHashI      h;
2488   const PetscInt *points;
2489   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2490   PetscInt        pStart, pEnd, part, q;
2491   PetscErrorCode  ierr;
2492 
2493   PetscFunctionBegin;
2494   PetscHashICreate(h);
2495   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2496   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2497   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2498   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2499   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2500   for (part = pStart; part < pEnd; ++part) {
2501     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2502 
2503     PetscHashIClear(h);
2504     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2505     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2506     /* Add all existing points to h */
2507     for (p = 0; p < numPoints; ++p) {
2508       const PetscInt point = points[off+p];
2509       PetscHashIAdd(h, point, 1);
2510     }
2511     PetscHashISize(h, nP);
2512     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2513     /* Add all points in next BFS level */
2514     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2515     for (p = 0; p < numPoints; ++p) {
2516       const PetscInt point = points[off+p];
2517       PetscInt       s     = start[point], e = start[point+1], a;
2518 
2519       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2520     }
2521     PetscHashISize(h, numNewPoints);
2522     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2523     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2524     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2525     totPoints += numNewPoints;
2526   }
2527   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2528   PetscHashIDestroy(h);
2529   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2530   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2531   for (part = pStart, q = 0; part < pEnd; ++part) {
2532     PetscInt numPoints, p;
2533 
2534     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2535     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2536     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2537   }
2538   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2539   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2540   PetscFunctionReturn(0);
2541 }
2542 
2543 #undef __FUNCT__
2544 #define __FUNCT__ "DMPlexCreatePartition"
2545 /*
2546   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2547 
2548   Collective on DM
2549 
2550   Input Parameters:
2551   + dm - The DM
2552   . height - The height for points in the partition
2553   - enlarge - Expand each partition with neighbors
2554 
2555   Output Parameters:
2556   + partSection - The PetscSection giving the division of points by partition
2557   . partition - The list of points by partition
2558   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2559   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2560 
2561   Level: developer
2562 
2563 .seealso DMPlexDistribute()
2564 */
2565 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2566 {
2567   PetscMPIInt    size;
2568   PetscErrorCode ierr;
2569 
2570   PetscFunctionBegin;
2571   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2572 
2573   *origPartSection = NULL;
2574   *origPartition   = NULL;
2575   if (size == 1) {
2576     PetscInt *points;
2577     PetscInt  cStart, cEnd, c;
2578 
2579     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2580     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2581     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2582     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2583     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2584     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2585     for (c = cStart; c < cEnd; ++c) points[c] = c;
2586     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2587     PetscFunctionReturn(0);
2588   }
2589   if (height == 0) {
2590     PetscInt  numVertices;
2591     PetscInt *start     = NULL;
2592     PetscInt *adjacency = NULL;
2593 
2594     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2595     if (1) {
2596 #if defined(PETSC_HAVE_CHACO)
2597       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2598 #endif
2599     } else {
2600 #if defined(PETSC_HAVE_PARMETIS)
2601       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2602 #endif
2603     }
2604     if (enlarge) {
2605       *origPartSection = *partSection;
2606       *origPartition   = *partition;
2607 
2608       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2609     }
2610     ierr = PetscFree(start);CHKERRQ(ierr);
2611     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2612 # if 0
2613   } else if (height == 1) {
2614     /* Build the dual graph for faces and partition the hypergraph */
2615     PetscInt numEdges;
2616 
2617     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2618     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2619     destroyCSR(numEdges, start, adjacency);
2620 #endif
2621   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2622   PetscFunctionReturn(0);
2623 }
2624 
2625 #undef __FUNCT__
2626 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2627 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2628 {
2629   /* const PetscInt  height = 0; */
2630   const PetscInt *partArray;
2631   PetscInt       *allPoints, *packPoints;
2632   PetscInt        rStart, rEnd, rank, pStart, pEnd, newSize;
2633   PetscErrorCode  ierr;
2634   PetscBT         bt;
2635   PetscSegBuffer  segpack,segpart;
2636 
2637   PetscFunctionBegin;
2638   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2639   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2640   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2641   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2642   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
2643   ierr = PetscBTCreate(pEnd-pStart,&bt);CHKERRQ(ierr);
2644   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);CHKERRQ(ierr);
2645   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);CHKERRQ(ierr);
2646   for (rank = rStart; rank < rEnd; ++rank) {
2647     PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints;
2648 
2649     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2650     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2651     for (p = 0; p < numPoints; ++p) {
2652       PetscInt  point   = partArray[offset+p], closureSize, c;
2653       PetscInt *closure = NULL;
2654 
2655       /* TODO Include support for height > 0 case */
2656       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2657       for (c=0; c<closureSize; c++) {
2658         PetscInt cpoint = closure[c*2];
2659         if (!PetscBTLookupSet(bt,cpoint-pStart)) {
2660           PetscInt *PETSC_RESTRICT pt;
2661           partSize++;
2662           ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr);
2663           *pt = cpoint;
2664         }
2665       }
2666       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2667     }
2668     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2669     ierr = PetscSegBufferGetInts(segpack,partSize,&placePoints);CHKERRQ(ierr);
2670     ierr = PetscSegBufferExtractTo(segpart,placePoints);CHKERRQ(ierr);
2671     ierr = PetscSortInt(partSize,placePoints);CHKERRQ(ierr);
2672     for (p=0; p<partSize; p++) {ierr = PetscBTClear(bt,placePoints[p]-pStart);CHKERRQ(ierr);}
2673   }
2674   ierr = PetscBTDestroy(&bt);CHKERRQ(ierr);
2675   ierr = PetscSegBufferDestroy(&segpart);CHKERRQ(ierr);
2676 
2677   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2678   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2679   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2680 
2681   ierr = PetscSegBufferExtractInPlace(segpack,&packPoints);CHKERRQ(ierr);
2682   for (rank = rStart; rank < rEnd; ++rank) {
2683     PetscInt numPoints, offset;
2684 
2685     ierr = PetscSectionGetDof(*section, rank, &numPoints);CHKERRQ(ierr);
2686     ierr = PetscSectionGetOffset(*section, rank, &offset);CHKERRQ(ierr);
2687     ierr = PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));CHKERRQ(ierr);
2688     packPoints += numPoints;
2689   }
2690 
2691   ierr = PetscSegBufferDestroy(&segpack);CHKERRQ(ierr);
2692   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
2693   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2694   PetscFunctionReturn(0);
2695 }
2696 
2697 #undef __FUNCT__
2698 #define __FUNCT__ "DMPlexDistributeField"
2699 /*
2700   Input Parameters:
2701 . originalSection
2702 , originalVec
2703 
2704   Output Parameters:
2705 . newSection
2706 . newVec
2707 */
2708 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
2709 {
2710   PetscSF        fieldSF;
2711   PetscInt      *remoteOffsets, fieldSize;
2712   PetscScalar   *originalValues, *newValues;
2713   PetscErrorCode ierr;
2714 
2715   PetscFunctionBegin;
2716   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
2717 
2718   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
2719   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
2720   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
2721 
2722   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
2723   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
2724   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
2725   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2726   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2727   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
2728   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
2729   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
2730   PetscFunctionReturn(0);
2731 }
2732 
2733 #undef __FUNCT__
2734 #define __FUNCT__ "DMPlexDistribute"
2735 /*@C
2736   DMPlexDistribute - Distributes the mesh and any associated sections.
2737 
2738   Not Collective
2739 
2740   Input Parameter:
2741 + dm  - The original DMPlex object
2742 . partitioner - The partitioning package, or NULL for the default
2743 - overlap - The overlap of partitions, 0 is the default
2744 
2745   Output Parameter:
2746 . parallelMesh - The distributed DMPlex object, or NULL
2747 
2748   Note: If the mesh was not distributed, the return value is NULL
2749 
2750   Level: intermediate
2751 
2752 .keywords: mesh, elements
2753 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
2754 @*/
2755 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
2756 {
2757   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
2758   MPI_Comm               comm;
2759   const PetscInt         height = 0;
2760   PetscInt               dim, numRemoteRanks;
2761   IS                     origCellPart,        cellPart,        part;
2762   PetscSection           origCellPartSection, cellPartSection, partSection;
2763   PetscSFNode           *remoteRanks;
2764   PetscSF                partSF, pointSF, coneSF;
2765   ISLocalToGlobalMapping renumbering;
2766   PetscSection           originalConeSection, newConeSection;
2767   PetscInt              *remoteOffsets;
2768   PetscInt              *cones, *newCones, newConesSize;
2769   PetscBool              flg;
2770   PetscMPIInt            rank, numProcs, p;
2771   PetscErrorCode         ierr;
2772 
2773   PetscFunctionBegin;
2774   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2775   PetscValidPointer(dmParallel,4);
2776 
2777   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2778   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2779   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2780   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
2781 
2782   *dmParallel = NULL;
2783   if (numProcs == 1) PetscFunctionReturn(0);
2784 
2785   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2786   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
2787   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
2788   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
2789   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
2790   if (!rank) numRemoteRanks = numProcs;
2791   else       numRemoteRanks = 0;
2792   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
2793   for (p = 0; p < numRemoteRanks; ++p) {
2794     remoteRanks[p].rank  = p;
2795     remoteRanks[p].index = 0;
2796   }
2797   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
2798   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
2799   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
2800   if (flg) {
2801     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
2802     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2803     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
2804     if (origCellPart) {
2805       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
2806       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2807       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
2808     }
2809     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
2810   }
2811   /* Close the partition over the mesh */
2812   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
2813   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
2814   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
2815   /* Create new mesh */
2816   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
2817   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
2818   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
2819   pmesh = (DM_Plex*) (*dmParallel)->data;
2820   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
2821   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
2822   if (flg) {
2823     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
2824     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2825     ierr = ISView(part, NULL);CHKERRQ(ierr);
2826     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
2827     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
2828     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
2829   }
2830   /* Distribute cone section */
2831   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
2832   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
2833   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
2834   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
2835   {
2836     PetscInt pStart, pEnd, p;
2837 
2838     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
2839     for (p = pStart; p < pEnd; ++p) {
2840       PetscInt coneSize;
2841       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
2842       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
2843     }
2844   }
2845   /* Communicate and renumber cones */
2846   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
2847   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2848   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
2849   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2850   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2851   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
2852   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
2853   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
2854   if (flg) {
2855     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
2856     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2857     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
2858     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2859     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
2860   }
2861   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
2862   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
2863   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2864   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2865   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
2866   /* Create supports and stratify sieve */
2867   {
2868     PetscInt pStart, pEnd;
2869 
2870     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2871     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2872   }
2873   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
2874   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
2875   /* Distribute Coordinates */
2876   {
2877     PetscSection originalCoordSection, newCoordSection;
2878     Vec          originalCoordinates, newCoordinates;
2879     const char  *name;
2880 
2881     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
2882     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
2883     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
2884     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
2885     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
2886     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
2887 
2888     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
2889     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
2890     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
2891   }
2892   /* Distribute labels */
2893   {
2894     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
2895     PetscInt numLabels = 0, l;
2896 
2897     /* Bcast number of labels */
2898     while (next) {
2899       ++numLabels; next = next->next;
2900     }
2901     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2902     next = mesh->labels;
2903     for (l = 0; l < numLabels; ++l) {
2904       DMLabel         newLabel;
2905       const PetscInt *partArray;
2906       char           *name;
2907       PetscInt       *stratumSizes = NULL, *points = NULL;
2908       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
2909       PetscInt        nameSize, s, p;
2910       PetscBool       isdepth;
2911       size_t          len = 0;
2912 
2913       /* Bcast name (could filter for no points) */
2914       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
2915       nameSize = len;
2916       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2917       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
2918       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
2919       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
2920       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
2921       if (isdepth) {            /* skip because "depth" is not distributed */
2922         ierr = PetscFree(name);CHKERRQ(ierr);
2923         if (!rank) next = next->next;
2924         continue;
2925       }
2926       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
2927       newLabel->name = name;
2928       /* Bcast numStrata (could filter for no points in stratum) */
2929       if (!rank) newLabel->numStrata = next->numStrata;
2930       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2931       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
2932                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
2933                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
2934       /* Bcast stratumValues (could filter for no points in stratum) */
2935       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
2936       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2937       /* Find size on each process and Scatter */
2938       if (!rank) {
2939         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
2940         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
2941         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
2942         for (s = 0; s < next->numStrata; ++s) {
2943           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2944             const PetscInt point = next->points[p];
2945             PetscInt       proc;
2946 
2947             for (proc = 0; proc < numProcs; ++proc) {
2948               PetscInt dof, off, pPart;
2949 
2950               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2951               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2952               for (pPart = off; pPart < off+dof; ++pPart) {
2953                 if (partArray[pPart] == point) {
2954                   ++stratumSizes[proc*next->numStrata+s];
2955                   break;
2956                 }
2957               }
2958             }
2959           }
2960         }
2961         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
2962       }
2963       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2964       /* Calculate stratumOffsets */
2965       newLabel->stratumOffsets[0] = 0;
2966       for (s = 0; s < newLabel->numStrata; ++s) {
2967         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
2968       }
2969       /* Pack points and Scatter */
2970       if (!rank) {
2971         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
2972         displs[0] = 0;
2973         for (p = 0; p < numProcs; ++p) {
2974           sendcnts[p] = 0;
2975           for (s = 0; s < next->numStrata; ++s) {
2976             sendcnts[p] += stratumSizes[p*next->numStrata+s];
2977           }
2978           offsets[p]  = displs[p];
2979           displs[p+1] = displs[p] + sendcnts[p];
2980         }
2981         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
2982         for (s = 0; s < next->numStrata; ++s) {
2983           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2984             const PetscInt point = next->points[p];
2985             PetscInt       proc;
2986 
2987             for (proc = 0; proc < numProcs; ++proc) {
2988               PetscInt dof, off, pPart;
2989 
2990               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2991               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2992               for (pPart = off; pPart < off+dof; ++pPart) {
2993                 if (partArray[pPart] == point) {
2994                   points[offsets[proc]++] = point;
2995                   break;
2996                 }
2997               }
2998             }
2999           }
3000         }
3001       }
3002       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3003       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3004       ierr = PetscFree(points);CHKERRQ(ierr);
3005       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3006       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3007       /* Renumber points */
3008       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3009       /* Sort points */
3010       for (s = 0; s < newLabel->numStrata; ++s) {
3011         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3012       }
3013       /* Insert into list */
3014       if (newNext) newNext->next = newLabel;
3015       else pmesh->labels = newLabel;
3016       newNext = newLabel;
3017       if (!rank) next = next->next;
3018     }
3019   }
3020   /* Cleanup Partition */
3021   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3022   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3023   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3024   ierr = ISDestroy(&part);CHKERRQ(ierr);
3025   /* Create point SF for parallel mesh */
3026   {
3027     const PetscInt *leaves;
3028     PetscSFNode    *remotePoints, *rowners, *lowners;
3029     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3030     PetscInt        pStart, pEnd;
3031 
3032     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3033     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3034     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3035     for (p=0; p<numRoots; p++) {
3036       rowners[p].rank  = -1;
3037       rowners[p].index = -1;
3038     }
3039     if (origCellPart) {
3040       /* Make sure cells in the original partition are not assigned to other procs */
3041       const PetscInt *origCells;
3042 
3043       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3044       for (p = 0; p < numProcs; ++p) {
3045         PetscInt dof, off, d;
3046 
3047         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3048         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3049         for (d = off; d < off+dof; ++d) {
3050           rowners[origCells[d]].rank = p;
3051         }
3052       }
3053       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3054     }
3055     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3056     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3057 
3058     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3059     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3060     for (p = 0; p < numLeaves; ++p) {
3061       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3062         lowners[p].rank  = rank;
3063         lowners[p].index = leaves ? leaves[p] : p;
3064       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3065         lowners[p].rank  = -2;
3066         lowners[p].index = -2;
3067       }
3068     }
3069     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3070       rowners[p].rank  = -3;
3071       rowners[p].index = -3;
3072     }
3073     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3074     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3075     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3076     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3077     for (p = 0; p < numLeaves; ++p) {
3078       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3079       if (lowners[p].rank != rank) ++numGhostPoints;
3080     }
3081     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3082     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3083     for (p = 0, gp = 0; p < numLeaves; ++p) {
3084       if (lowners[p].rank != rank) {
3085         ghostPoints[gp]        = leaves ? leaves[p] : p;
3086         remotePoints[gp].rank  = lowners[p].rank;
3087         remotePoints[gp].index = lowners[p].index;
3088         ++gp;
3089       }
3090     }
3091     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3092     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3093     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3094   }
3095   /* Cleanup */
3096   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3097   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3098   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3099   PetscFunctionReturn(0);
3100 }
3101 
3102 #undef __FUNCT__
3103 #define __FUNCT__ "DMPlexInvertCells_Internal"
3104 /* This is to fix the tetrahedron orientation from TetGen */
3105 PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt numCells, PetscInt numCorners, int cells[])
3106 {
3107   PetscInt c;
3108 
3109   PetscFunctionBegin;
3110   if (numCorners != 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot invert cells with %d corners", numCorners);
3111   for (c = 0; c < numCells; ++c) {
3112     int *cone = &cells[c*4], tmpc;
3113 
3114     tmpc    = cone[0];
3115     cone[0] = cone[1];
3116     cone[1] = tmpc;
3117   }
3118   PetscFunctionReturn(0);
3119 }
3120 
3121 #if defined(PETSC_HAVE_TRIANGLE)
3122 #include <triangle.h>
3123 
3124 #undef __FUNCT__
3125 #define __FUNCT__ "InitInput_Triangle"
3126 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3127 {
3128   PetscFunctionBegin;
3129   inputCtx->numberofpoints             = 0;
3130   inputCtx->numberofpointattributes    = 0;
3131   inputCtx->pointlist                  = NULL;
3132   inputCtx->pointattributelist         = NULL;
3133   inputCtx->pointmarkerlist            = NULL;
3134   inputCtx->numberofsegments           = 0;
3135   inputCtx->segmentlist                = NULL;
3136   inputCtx->segmentmarkerlist          = NULL;
3137   inputCtx->numberoftriangleattributes = 0;
3138   inputCtx->trianglelist               = NULL;
3139   inputCtx->numberofholes              = 0;
3140   inputCtx->holelist                   = NULL;
3141   inputCtx->numberofregions            = 0;
3142   inputCtx->regionlist                 = NULL;
3143   PetscFunctionReturn(0);
3144 }
3145 
3146 #undef __FUNCT__
3147 #define __FUNCT__ "InitOutput_Triangle"
3148 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3149 {
3150   PetscFunctionBegin;
3151   outputCtx->numberofpoints        = 0;
3152   outputCtx->pointlist             = NULL;
3153   outputCtx->pointattributelist    = NULL;
3154   outputCtx->pointmarkerlist       = NULL;
3155   outputCtx->numberoftriangles     = 0;
3156   outputCtx->trianglelist          = NULL;
3157   outputCtx->triangleattributelist = NULL;
3158   outputCtx->neighborlist          = NULL;
3159   outputCtx->segmentlist           = NULL;
3160   outputCtx->segmentmarkerlist     = NULL;
3161   outputCtx->numberofedges         = 0;
3162   outputCtx->edgelist              = NULL;
3163   outputCtx->edgemarkerlist        = NULL;
3164   PetscFunctionReturn(0);
3165 }
3166 
3167 #undef __FUNCT__
3168 #define __FUNCT__ "FiniOutput_Triangle"
3169 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3170 {
3171   PetscFunctionBegin;
3172   free(outputCtx->pointmarkerlist);
3173   free(outputCtx->edgelist);
3174   free(outputCtx->edgemarkerlist);
3175   free(outputCtx->trianglelist);
3176   free(outputCtx->neighborlist);
3177   PetscFunctionReturn(0);
3178 }
3179 
3180 #undef __FUNCT__
3181 #define __FUNCT__ "DMPlexGenerate_Triangle"
3182 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3183 {
3184   MPI_Comm             comm;
3185   PetscInt             dim              = 2;
3186   const PetscBool      createConvexHull = PETSC_FALSE;
3187   const PetscBool      constrained      = PETSC_FALSE;
3188   struct triangulateio in;
3189   struct triangulateio out;
3190   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3191   PetscMPIInt          rank;
3192   PetscErrorCode       ierr;
3193 
3194   PetscFunctionBegin;
3195   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3196   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3197   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3198   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3199   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3200 
3201   in.numberofpoints = vEnd - vStart;
3202   if (in.numberofpoints > 0) {
3203     PetscSection coordSection;
3204     Vec          coordinates;
3205     PetscScalar *array;
3206 
3207     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3208     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3209     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3210     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3211     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3212     for (v = vStart; v < vEnd; ++v) {
3213       const PetscInt idx = v - vStart;
3214       PetscInt       off, d;
3215 
3216       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3217       for (d = 0; d < dim; ++d) {
3218         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3219       }
3220       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3221     }
3222     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3223   }
3224   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3225   in.numberofsegments = eEnd - eStart;
3226   if (in.numberofsegments > 0) {
3227     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
3228     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
3229     for (e = eStart; e < eEnd; ++e) {
3230       const PetscInt  idx = e - eStart;
3231       const PetscInt *cone;
3232 
3233       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3234 
3235       in.segmentlist[idx*2+0] = cone[0] - vStart;
3236       in.segmentlist[idx*2+1] = cone[1] - vStart;
3237 
3238       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3239     }
3240   }
3241 #if 0 /* Do not currently support holes */
3242   PetscReal *holeCoords;
3243   PetscInt   h, d;
3244 
3245   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3246   if (in.numberofholes > 0) {
3247     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3248     for (h = 0; h < in.numberofholes; ++h) {
3249       for (d = 0; d < dim; ++d) {
3250         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3251       }
3252     }
3253   }
3254 #endif
3255   if (!rank) {
3256     char args[32];
3257 
3258     /* Take away 'Q' for verbose output */
3259     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3260     if (createConvexHull) {
3261       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3262     }
3263     if (constrained) {
3264       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3265     }
3266     triangulate(args, &in, &out, NULL);
3267   }
3268   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3269   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3270   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3271   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3272   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3273 
3274   {
3275     const PetscInt numCorners  = 3;
3276     const PetscInt numCells    = out.numberoftriangles;
3277     const PetscInt numVertices = out.numberofpoints;
3278     const int     *cells      = out.trianglelist;
3279     const double  *meshCoords = out.pointlist;
3280 
3281     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3282     /* Set labels */
3283     for (v = 0; v < numVertices; ++v) {
3284       if (out.pointmarkerlist[v]) {
3285         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3286       }
3287     }
3288     if (interpolate) {
3289       for (e = 0; e < out.numberofedges; e++) {
3290         if (out.edgemarkerlist[e]) {
3291           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3292           const PetscInt *edges;
3293           PetscInt        numEdges;
3294 
3295           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3296           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3297           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3298           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3299         }
3300       }
3301     }
3302     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3303   }
3304 #if 0 /* Do not currently support holes */
3305   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3306 #endif
3307   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3308   PetscFunctionReturn(0);
3309 }
3310 
3311 #undef __FUNCT__
3312 #define __FUNCT__ "DMPlexRefine_Triangle"
3313 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3314 {
3315   MPI_Comm             comm;
3316   PetscInt             dim  = 2;
3317   struct triangulateio in;
3318   struct triangulateio out;
3319   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3320   PetscMPIInt          rank;
3321   PetscErrorCode       ierr;
3322 
3323   PetscFunctionBegin;
3324   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3325   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3326   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3327   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3328   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3329   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3330   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3331 
3332   in.numberofpoints = vEnd - vStart;
3333   if (in.numberofpoints > 0) {
3334     PetscSection coordSection;
3335     Vec          coordinates;
3336     PetscScalar *array;
3337 
3338     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3339     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3340     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3341     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3342     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3343     for (v = vStart; v < vEnd; ++v) {
3344       const PetscInt idx = v - vStart;
3345       PetscInt       off, d;
3346 
3347       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3348       for (d = 0; d < dim; ++d) {
3349         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3350       }
3351       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3352     }
3353     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3354   }
3355   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3356 
3357   in.numberofcorners   = 3;
3358   in.numberoftriangles = cEnd - cStart;
3359 
3360   in.trianglearealist  = (double*) maxVolumes;
3361   if (in.numberoftriangles > 0) {
3362     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
3363     for (c = cStart; c < cEnd; ++c) {
3364       const PetscInt idx      = c - cStart;
3365       PetscInt      *closure = NULL;
3366       PetscInt       closureSize;
3367 
3368       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3369       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3370       for (v = 0; v < 3; ++v) {
3371         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3372       }
3373       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3374     }
3375   }
3376   /* TODO: Segment markers are missing on input */
3377 #if 0 /* Do not currently support holes */
3378   PetscReal *holeCoords;
3379   PetscInt   h, d;
3380 
3381   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3382   if (in.numberofholes > 0) {
3383     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3384     for (h = 0; h < in.numberofholes; ++h) {
3385       for (d = 0; d < dim; ++d) {
3386         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3387       }
3388     }
3389   }
3390 #endif
3391   if (!rank) {
3392     char args[32];
3393 
3394     /* Take away 'Q' for verbose output */
3395     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3396     triangulate(args, &in, &out, NULL);
3397   }
3398   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3399   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3400   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3401   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3402   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3403 
3404   {
3405     const PetscInt numCorners  = 3;
3406     const PetscInt numCells    = out.numberoftriangles;
3407     const PetscInt numVertices = out.numberofpoints;
3408     const int     *cells      = out.trianglelist;
3409     const double  *meshCoords = out.pointlist;
3410     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3411 
3412     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3413     /* Set labels */
3414     for (v = 0; v < numVertices; ++v) {
3415       if (out.pointmarkerlist[v]) {
3416         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3417       }
3418     }
3419     if (interpolate) {
3420       PetscInt e;
3421 
3422       for (e = 0; e < out.numberofedges; e++) {
3423         if (out.edgemarkerlist[e]) {
3424           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3425           const PetscInt *edges;
3426           PetscInt        numEdges;
3427 
3428           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3429           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3430           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3431           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3432         }
3433       }
3434     }
3435     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3436   }
3437 #if 0 /* Do not currently support holes */
3438   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3439 #endif
3440   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3441   PetscFunctionReturn(0);
3442 }
3443 #endif
3444 
3445 #if defined(PETSC_HAVE_TETGEN)
3446 #include <tetgen.h>
3447 #undef __FUNCT__
3448 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3449 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3450 {
3451   MPI_Comm       comm;
3452   const PetscInt dim  = 3;
3453   ::tetgenio     in;
3454   ::tetgenio     out;
3455   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3456   PetscMPIInt    rank;
3457   PetscErrorCode ierr;
3458 
3459   PetscFunctionBegin;
3460   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3461   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3462   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3463   in.numberofpoints = vEnd - vStart;
3464   if (in.numberofpoints > 0) {
3465     PetscSection coordSection;
3466     Vec          coordinates;
3467     PetscScalar *array;
3468 
3469     in.pointlist       = new double[in.numberofpoints*dim];
3470     in.pointmarkerlist = new int[in.numberofpoints];
3471 
3472     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3473     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3474     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3475     for (v = vStart; v < vEnd; ++v) {
3476       const PetscInt idx = v - vStart;
3477       PetscInt       off, d;
3478 
3479       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3480       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3481       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3482     }
3483     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3484   }
3485   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3486 
3487   in.numberoffacets = fEnd - fStart;
3488   if (in.numberoffacets > 0) {
3489     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3490     in.facetmarkerlist = new int[in.numberoffacets];
3491     for (f = fStart; f < fEnd; ++f) {
3492       const PetscInt idx     = f - fStart;
3493       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3494 
3495       in.facetlist[idx].numberofpolygons = 1;
3496       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3497       in.facetlist[idx].numberofholes    = 0;
3498       in.facetlist[idx].holelist         = NULL;
3499 
3500       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3501       for (p = 0; p < numPoints*2; p += 2) {
3502         const PetscInt point = points[p];
3503         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3504       }
3505 
3506       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3507       poly->numberofvertices = numVertices;
3508       poly->vertexlist       = new int[poly->numberofvertices];
3509       for (v = 0; v < numVertices; ++v) {
3510         const PetscInt vIdx = points[v] - vStart;
3511         poly->vertexlist[v] = vIdx;
3512       }
3513       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3514       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3515     }
3516   }
3517   if (!rank) {
3518     char args[32];
3519 
3520     /* Take away 'Q' for verbose output */
3521     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3522     ::tetrahedralize(args, &in, &out);
3523   }
3524   {
3525     const PetscInt numCorners  = 4;
3526     const PetscInt numCells    = out.numberoftetrahedra;
3527     const PetscInt numVertices = out.numberofpoints;
3528     const double   *meshCoords = out.pointlist;
3529     int            *cells      = out.tetrahedronlist;
3530 
3531     ierr = DMPlexInvertCells_Internal(numCells, numCorners, cells);CHKERRQ(ierr);
3532     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3533     /* Set labels */
3534     for (v = 0; v < numVertices; ++v) {
3535       if (out.pointmarkerlist[v]) {
3536         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3537       }
3538     }
3539     if (interpolate) {
3540       PetscInt e;
3541 
3542       for (e = 0; e < out.numberofedges; e++) {
3543         if (out.edgemarkerlist[e]) {
3544           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3545           const PetscInt *edges;
3546           PetscInt        numEdges;
3547 
3548           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3549           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3550           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3551           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3552         }
3553       }
3554       for (f = 0; f < out.numberoftrifaces; f++) {
3555         if (out.trifacemarkerlist[f]) {
3556           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3557           const PetscInt *faces;
3558           PetscInt        numFaces;
3559 
3560           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3561           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3562           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3563           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3564         }
3565       }
3566     }
3567     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3568   }
3569   PetscFunctionReturn(0);
3570 }
3571 
3572 #undef __FUNCT__
3573 #define __FUNCT__ "DMPlexRefine_Tetgen"
3574 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3575 {
3576   MPI_Comm       comm;
3577   const PetscInt dim  = 3;
3578   ::tetgenio     in;
3579   ::tetgenio     out;
3580   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3581   PetscMPIInt    rank;
3582   PetscErrorCode ierr;
3583 
3584   PetscFunctionBegin;
3585   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3586   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3587   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3588   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3589   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3590 
3591   in.numberofpoints = vEnd - vStart;
3592   if (in.numberofpoints > 0) {
3593     PetscSection coordSection;
3594     Vec          coordinates;
3595     PetscScalar *array;
3596 
3597     in.pointlist       = new double[in.numberofpoints*dim];
3598     in.pointmarkerlist = new int[in.numberofpoints];
3599 
3600     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3601     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3602     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3603     for (v = vStart; v < vEnd; ++v) {
3604       const PetscInt idx = v - vStart;
3605       PetscInt       off, d;
3606 
3607       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3608       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3609       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3610     }
3611     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3612   }
3613   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3614 
3615   in.numberofcorners       = 4;
3616   in.numberoftetrahedra    = cEnd - cStart;
3617   in.tetrahedronvolumelist = (double*) maxVolumes;
3618   if (in.numberoftetrahedra > 0) {
3619     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3620     for (c = cStart; c < cEnd; ++c) {
3621       const PetscInt idx      = c - cStart;
3622       PetscInt      *closure = NULL;
3623       PetscInt       closureSize;
3624 
3625       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3626       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3627       for (v = 0; v < 4; ++v) {
3628         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3629       }
3630       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3631     }
3632   }
3633   /* TODO: Put in boundary faces with markers */
3634   if (!rank) {
3635     char args[32];
3636 
3637     /* Take away 'Q' for verbose output */
3638     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3639     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3640     ::tetrahedralize(args, &in, &out);
3641   }
3642   in.tetrahedronvolumelist = NULL;
3643 
3644   {
3645     const PetscInt numCorners  = 4;
3646     const PetscInt numCells    = out.numberoftetrahedra;
3647     const PetscInt numVertices = out.numberofpoints;
3648     const double   *meshCoords = out.pointlist;
3649     int            *cells      = out.tetrahedronlist;
3650 
3651     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3652 
3653     ierr = DMPlexInvertCells_Internal(numCells, numCorners, cells);CHKERRQ(ierr);
3654     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3655     /* Set labels */
3656     for (v = 0; v < numVertices; ++v) {
3657       if (out.pointmarkerlist[v]) {
3658         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3659       }
3660     }
3661     if (interpolate) {
3662       PetscInt e, f;
3663 
3664       for (e = 0; e < out.numberofedges; e++) {
3665         if (out.edgemarkerlist[e]) {
3666           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3667           const PetscInt *edges;
3668           PetscInt        numEdges;
3669 
3670           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3671           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3672           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3673           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3674         }
3675       }
3676       for (f = 0; f < out.numberoftrifaces; f++) {
3677         if (out.trifacemarkerlist[f]) {
3678           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3679           const PetscInt *faces;
3680           PetscInt        numFaces;
3681 
3682           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3683           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3684           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3685           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3686         }
3687       }
3688     }
3689     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3690   }
3691   PetscFunctionReturn(0);
3692 }
3693 #endif
3694 
3695 #if defined(PETSC_HAVE_CTETGEN)
3696 #include "ctetgen.h"
3697 
3698 #undef __FUNCT__
3699 #define __FUNCT__ "DMPlexGenerate_CTetgen"
3700 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3701 {
3702   MPI_Comm       comm;
3703   const PetscInt dim  = 3;
3704   PLC           *in, *out;
3705   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3706   PetscMPIInt    rank;
3707   PetscErrorCode ierr;
3708 
3709   PetscFunctionBegin;
3710   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3711   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3712   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3713   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3714   ierr = PLCCreate(&in);CHKERRQ(ierr);
3715   ierr = PLCCreate(&out);CHKERRQ(ierr);
3716 
3717   in->numberofpoints = vEnd - vStart;
3718   if (in->numberofpoints > 0) {
3719     PetscSection coordSection;
3720     Vec          coordinates;
3721     PetscScalar *array;
3722 
3723     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3724     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3725     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3726     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3727     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3728     for (v = vStart; v < vEnd; ++v) {
3729       const PetscInt idx = v - vStart;
3730       PetscInt       off, d, m;
3731 
3732       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3733       for (d = 0; d < dim; ++d) {
3734         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3735       }
3736       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
3737 
3738       in->pointmarkerlist[idx] = (int) m;
3739     }
3740     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3741   }
3742   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3743 
3744   in->numberoffacets = fEnd - fStart;
3745   if (in->numberoffacets > 0) {
3746     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
3747     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
3748     for (f = fStart; f < fEnd; ++f) {
3749       const PetscInt idx     = f - fStart;
3750       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3751       polygon       *poly;
3752 
3753       in->facetlist[idx].numberofpolygons = 1;
3754 
3755       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
3756 
3757       in->facetlist[idx].numberofholes    = 0;
3758       in->facetlist[idx].holelist         = NULL;
3759 
3760       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3761       for (p = 0; p < numPoints*2; p += 2) {
3762         const PetscInt point = points[p];
3763         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3764       }
3765 
3766       poly                   = in->facetlist[idx].polygonlist;
3767       poly->numberofvertices = numVertices;
3768       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
3769       for (v = 0; v < numVertices; ++v) {
3770         const PetscInt vIdx = points[v] - vStart;
3771         poly->vertexlist[v] = vIdx;
3772       }
3773       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
3774       in->facetmarkerlist[idx] = (int) m;
3775       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3776     }
3777   }
3778   if (!rank) {
3779     TetGenOpts t;
3780 
3781     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3782     t.in        = boundary; /* Should go away */
3783     t.plc       = 1;
3784     t.quality   = 1;
3785     t.edgesout  = 1;
3786     t.zeroindex = 1;
3787     t.quiet     = 1;
3788     t.verbose   = verbose;
3789     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
3790     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3791   }
3792   {
3793     const PetscInt numCorners  = 4;
3794     const PetscInt numCells    = out->numberoftetrahedra;
3795     const PetscInt numVertices = out->numberofpoints;
3796     const double   *meshCoords = out->pointlist;
3797     int            *cells      = out->tetrahedronlist;
3798 
3799     ierr = DMPlexInvertCells_Internal(numCells, numCorners, cells);CHKERRQ(ierr);
3800     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3801     /* Set labels */
3802     for (v = 0; v < numVertices; ++v) {
3803       if (out->pointmarkerlist[v]) {
3804         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3805       }
3806     }
3807     if (interpolate) {
3808       PetscInt e;
3809 
3810       for (e = 0; e < out->numberofedges; e++) {
3811         if (out->edgemarkerlist[e]) {
3812           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3813           const PetscInt *edges;
3814           PetscInt        numEdges;
3815 
3816           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3817           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3818           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3819           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3820         }
3821       }
3822       for (f = 0; f < out->numberoftrifaces; f++) {
3823         if (out->trifacemarkerlist[f]) {
3824           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3825           const PetscInt *faces;
3826           PetscInt        numFaces;
3827 
3828           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3829           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3830           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3831           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3832         }
3833       }
3834     }
3835     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3836   }
3837 
3838   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3839   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3840   PetscFunctionReturn(0);
3841 }
3842 
3843 #undef __FUNCT__
3844 #define __FUNCT__ "DMPlexRefine_CTetgen"
3845 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
3846 {
3847   MPI_Comm       comm;
3848   const PetscInt dim  = 3;
3849   PLC           *in, *out;
3850   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3851   PetscMPIInt    rank;
3852   PetscErrorCode ierr;
3853 
3854   PetscFunctionBegin;
3855   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3856   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3857   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3858   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3859   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3860   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3861   ierr = PLCCreate(&in);CHKERRQ(ierr);
3862   ierr = PLCCreate(&out);CHKERRQ(ierr);
3863 
3864   in->numberofpoints = vEnd - vStart;
3865   if (in->numberofpoints > 0) {
3866     PetscSection coordSection;
3867     Vec          coordinates;
3868     PetscScalar *array;
3869 
3870     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3871     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3872     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3873     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3874     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3875     for (v = vStart; v < vEnd; ++v) {
3876       const PetscInt idx = v - vStart;
3877       PetscInt       off, d, m;
3878 
3879       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3880       for (d = 0; d < dim; ++d) {
3881         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3882       }
3883       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
3884 
3885       in->pointmarkerlist[idx] = (int) m;
3886     }
3887     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3888   }
3889   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3890 
3891   in->numberofcorners       = 4;
3892   in->numberoftetrahedra    = cEnd - cStart;
3893   in->tetrahedronvolumelist = maxVolumes;
3894   if (in->numberoftetrahedra > 0) {
3895     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
3896     for (c = cStart; c < cEnd; ++c) {
3897       const PetscInt idx      = c - cStart;
3898       PetscInt      *closure = NULL;
3899       PetscInt       closureSize;
3900 
3901       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3902       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3903       for (v = 0; v < 4; ++v) {
3904         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3905       }
3906       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3907     }
3908   }
3909   if (!rank) {
3910     TetGenOpts t;
3911 
3912     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3913 
3914     t.in        = dm; /* Should go away */
3915     t.refine    = 1;
3916     t.varvolume = 1;
3917     t.quality   = 1;
3918     t.edgesout  = 1;
3919     t.zeroindex = 1;
3920     t.quiet     = 1;
3921     t.verbose   = verbose; /* Change this */
3922 
3923     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
3924     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3925   }
3926   {
3927     const PetscInt numCorners  = 4;
3928     const PetscInt numCells    = out->numberoftetrahedra;
3929     const PetscInt numVertices = out->numberofpoints;
3930     const double   *meshCoords = out->pointlist;
3931     int            *cells      = out->tetrahedronlist;
3932     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3933 
3934     ierr = DMPlexInvertCells_Internal(numCells, numCorners, cells);CHKERRQ(ierr);
3935     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3936     /* Set labels */
3937     for (v = 0; v < numVertices; ++v) {
3938       if (out->pointmarkerlist[v]) {
3939         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3940       }
3941     }
3942     if (interpolate) {
3943       PetscInt e, f;
3944 
3945       for (e = 0; e < out->numberofedges; e++) {
3946         if (out->edgemarkerlist[e]) {
3947           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3948           const PetscInt *edges;
3949           PetscInt        numEdges;
3950 
3951           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3952           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3953           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3954           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3955         }
3956       }
3957       for (f = 0; f < out->numberoftrifaces; f++) {
3958         if (out->trifacemarkerlist[f]) {
3959           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3960           const PetscInt *faces;
3961           PetscInt        numFaces;
3962 
3963           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3964           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3965           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3966           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3967         }
3968       }
3969     }
3970     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3971   }
3972   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3973   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3974   PetscFunctionReturn(0);
3975 }
3976 #endif
3977 
3978 #undef __FUNCT__
3979 #define __FUNCT__ "DMPlexGenerate"
3980 /*@C
3981   DMPlexGenerate - Generates a mesh.
3982 
3983   Not Collective
3984 
3985   Input Parameters:
3986 + boundary - The DMPlex boundary object
3987 . name - The mesh generation package name
3988 - interpolate - Flag to create intermediate mesh elements
3989 
3990   Output Parameter:
3991 . mesh - The DMPlex object
3992 
3993   Level: intermediate
3994 
3995 .keywords: mesh, elements
3996 .seealso: DMPlexCreate(), DMRefine()
3997 @*/
3998 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
3999 {
4000   PetscInt       dim;
4001   char           genname[1024];
4002   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4003   PetscErrorCode ierr;
4004 
4005   PetscFunctionBegin;
4006   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
4007   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
4008   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
4009   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
4010   if (flg) name = genname;
4011   if (name) {
4012     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
4013     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
4014     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
4015   }
4016   switch (dim) {
4017   case 1:
4018     if (!name || isTriangle) {
4019 #if defined(PETSC_HAVE_TRIANGLE)
4020       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
4021 #else
4022       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4023 #endif
4024     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4025     break;
4026   case 2:
4027     if (!name || isCTetgen) {
4028 #if defined(PETSC_HAVE_CTETGEN)
4029       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4030 #else
4031       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4032 #endif
4033     } else if (isTetgen) {
4034 #if defined(PETSC_HAVE_TETGEN)
4035       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4036 #else
4037       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4038 #endif
4039     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4040     break;
4041   default:
4042     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4043   }
4044   PetscFunctionReturn(0);
4045 }
4046 
4047 typedef PetscInt CellRefiner;
4048 
4049 #undef __FUNCT__
4050 #define __FUNCT__ "GetDepthStart_Private"
4051 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
4052 {
4053   PetscFunctionBegin;
4054   if (cStart) *cStart = 0;
4055   if (vStart) *vStart = depthSize[depth];
4056   if (fStart) *fStart = depthSize[depth] + depthSize[0];
4057   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4058   PetscFunctionReturn(0);
4059 }
4060 
4061 #undef __FUNCT__
4062 #define __FUNCT__ "GetDepthEnd_Private"
4063 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
4064 {
4065   PetscFunctionBegin;
4066   if (cEnd) *cEnd = depthSize[depth];
4067   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
4068   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4069   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
4070   PetscFunctionReturn(0);
4071 }
4072 
4073 #undef __FUNCT__
4074 #define __FUNCT__ "CellRefinerGetSizes"
4075 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
4076 {
4077   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
4078   PetscErrorCode ierr;
4079 
4080   PetscFunctionBegin;
4081   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4082   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4083   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4084   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4085   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4086   switch (refiner) {
4087   case 1:
4088     /* Simplicial 2D */
4089     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
4090     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
4091     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
4092     break;
4093   case 3:
4094     /* Hybrid 2D */
4095     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4096     cMax = PetscMin(cEnd, cMax);
4097     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4098     fMax         = PetscMin(fEnd, fMax);
4099     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
4100     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 */
4101     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
4102     break;
4103   case 2:
4104     /* Hex 2D */
4105     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
4106     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
4107     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
4108     break;
4109   default:
4110     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4111   }
4112   PetscFunctionReturn(0);
4113 }
4114 
4115 #undef __FUNCT__
4116 #define __FUNCT__ "CellRefinerSetConeSizes"
4117 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4118 {
4119   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
4120   PetscErrorCode ierr;
4121 
4122   PetscFunctionBegin;
4123   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4124   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4125   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4126   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4127   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4128   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4129   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4130   switch (refiner) {
4131   case 1:
4132     /* Simplicial 2D */
4133     /* All cells have 3 faces */
4134     for (c = cStart; c < cEnd; ++c) {
4135       for (r = 0; r < 4; ++r) {
4136         const PetscInt newp = (c - cStart)*4 + r;
4137 
4138         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4139       }
4140     }
4141     /* Split faces have 2 vertices and the same cells as the parent */
4142     for (f = fStart; f < fEnd; ++f) {
4143       for (r = 0; r < 2; ++r) {
4144         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4145         PetscInt       size;
4146 
4147         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4148         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4149         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4150       }
4151     }
4152     /* Interior faces have 2 vertices and 2 cells */
4153     for (c = cStart; c < cEnd; ++c) {
4154       for (r = 0; r < 3; ++r) {
4155         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4156 
4157         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4158         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4159       }
4160     }
4161     /* Old vertices have identical supports */
4162     for (v = vStart; v < vEnd; ++v) {
4163       const PetscInt newp = vStartNew + (v - vStart);
4164       PetscInt       size;
4165 
4166       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4167       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4168     }
4169     /* Face vertices have 2 + cells*2 supports */
4170     for (f = fStart; f < fEnd; ++f) {
4171       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4172       PetscInt       size;
4173 
4174       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4175       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
4176     }
4177     break;
4178   case 2:
4179     /* Hex 2D */
4180     /* All cells have 4 faces */
4181     for (c = cStart; c < cEnd; ++c) {
4182       for (r = 0; r < 4; ++r) {
4183         const PetscInt newp = (c - cStart)*4 + r;
4184 
4185         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4186       }
4187     }
4188     /* Split faces have 2 vertices and the same cells as the parent */
4189     for (f = fStart; f < fEnd; ++f) {
4190       for (r = 0; r < 2; ++r) {
4191         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4192         PetscInt       size;
4193 
4194         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4195         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4196         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4197       }
4198     }
4199     /* Interior faces have 2 vertices and 2 cells */
4200     for (c = cStart; c < cEnd; ++c) {
4201       for (r = 0; r < 4; ++r) {
4202         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4203 
4204         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4205         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4206       }
4207     }
4208     /* Old vertices have identical supports */
4209     for (v = vStart; v < vEnd; ++v) {
4210       const PetscInt newp = vStartNew + (v - vStart);
4211       PetscInt       size;
4212 
4213       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4214       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4215     }
4216     /* Face vertices have 2 + cells supports */
4217     for (f = fStart; f < fEnd; ++f) {
4218       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4219       PetscInt       size;
4220 
4221       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4222       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
4223     }
4224     /* Cell vertices have 4 supports */
4225     for (c = cStart; c < cEnd; ++c) {
4226       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4227 
4228       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
4229     }
4230     break;
4231   case 3:
4232     /* Hybrid 2D */
4233     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4234     cMax = PetscMin(cEnd, cMax);
4235     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4236     fMax = PetscMin(fEnd, fMax);
4237     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4238     /* Interior cells have 3 faces */
4239     for (c = cStart; c < cMax; ++c) {
4240       for (r = 0; r < 4; ++r) {
4241         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
4242 
4243         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4244       }
4245     }
4246     /* Hybrid cells have 4 faces */
4247     for (c = cMax; c < cEnd; ++c) {
4248       for (r = 0; r < 2; ++r) {
4249         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
4250 
4251         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4252       }
4253     }
4254     /* Interior split faces have 2 vertices and the same cells as the parent */
4255     for (f = fStart; f < fMax; ++f) {
4256       for (r = 0; r < 2; ++r) {
4257         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4258         PetscInt       size;
4259 
4260         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4261         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4262         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4263       }
4264     }
4265     /* Interior cell faces have 2 vertices and 2 cells */
4266     for (c = cStart; c < cMax; ++c) {
4267       for (r = 0; r < 3; ++r) {
4268         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4269 
4270         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4271         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4272       }
4273     }
4274     /* Hybrid faces have 2 vertices and the same cells */
4275     for (f = fMax; f < fEnd; ++f) {
4276       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4277       PetscInt       size;
4278 
4279       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4280       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4281       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4282     }
4283     /* Hybrid cell faces have 2 vertices and 2 cells */
4284     for (c = cMax; c < cEnd; ++c) {
4285       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4286 
4287       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4288       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4289     }
4290     /* Old vertices have identical supports */
4291     for (v = vStart; v < vEnd; ++v) {
4292       const PetscInt newp = vStartNew + (v - vStart);
4293       PetscInt       size;
4294 
4295       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4296       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4297     }
4298     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4299     for (f = fStart; f < fMax; ++f) {
4300       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4301       const PetscInt *support;
4302       PetscInt       size, newSize = 2, s;
4303 
4304       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4305       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4306       for (s = 0; s < size; ++s) {
4307         if (support[s] >= cMax) newSize += 1;
4308         else newSize += 2;
4309       }
4310       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
4311     }
4312     break;
4313   default:
4314     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4315   }
4316   PetscFunctionReturn(0);
4317 }
4318 
4319 #undef __FUNCT__
4320 #define __FUNCT__ "CellRefinerSetCones"
4321 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4322 {
4323   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;
4324   PetscInt       maxSupportSize, *supportRef;
4325   PetscErrorCode ierr;
4326 
4327   PetscFunctionBegin;
4328   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4329   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4330   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4331   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4332   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4333   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4334   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4335   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
4336   switch (refiner) {
4337   case 1:
4338     /* Simplicial 2D */
4339     /*
4340      2
4341      |\
4342      | \
4343      |  \
4344      |   \
4345      | C  \
4346      |     \
4347      |      \
4348      2---1---1
4349      |\  D  / \
4350      | 2   0   \
4351      |A \ /  B  \
4352      0---0-------1
4353      */
4354     /* All cells have 3 faces */
4355     for (c = cStart; c < cEnd; ++c) {
4356       const PetscInt  newp = cStartNew + (c - cStart)*4;
4357       const PetscInt *cone, *ornt;
4358       PetscInt        coneNew[3], orntNew[3];
4359 
4360       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4361       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4362       /* A triangle */
4363       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4364       orntNew[0] = ornt[0];
4365       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4366       orntNew[1] = -2;
4367       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4368       orntNew[2] = ornt[2];
4369       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4370       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4371 #if 1
4372       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);
4373       for (p = 0; p < 3; ++p) {
4374         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);
4375       }
4376 #endif
4377       /* B triangle */
4378       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4379       orntNew[0] = ornt[0];
4380       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4381       orntNew[1] = ornt[1];
4382       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4383       orntNew[2] = -2;
4384       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4385       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4386 #if 1
4387       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);
4388       for (p = 0; p < 3; ++p) {
4389         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);
4390       }
4391 #endif
4392       /* C triangle */
4393       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4394       orntNew[0] = -2;
4395       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4396       orntNew[1] = ornt[1];
4397       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4398       orntNew[2] = ornt[2];
4399       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4400       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4401 #if 1
4402       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);
4403       for (p = 0; p < 3; ++p) {
4404         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);
4405       }
4406 #endif
4407       /* D triangle */
4408       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4409       orntNew[0] = 0;
4410       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4411       orntNew[1] = 0;
4412       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4413       orntNew[2] = 0;
4414       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4415       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4416 #if 1
4417       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);
4418       for (p = 0; p < 3; ++p) {
4419         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);
4420       }
4421 #endif
4422     }
4423     /* Split faces have 2 vertices and the same cells as the parent */
4424     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4425     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4426     for (f = fStart; f < fEnd; ++f) {
4427       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4428 
4429       for (r = 0; r < 2; ++r) {
4430         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4431         const PetscInt *cone, *support;
4432         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4433 
4434         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4435         coneNew[0]       = vStartNew + (cone[0] - vStart);
4436         coneNew[1]       = vStartNew + (cone[1] - vStart);
4437         coneNew[(r+1)%2] = newv;
4438         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4439 #if 1
4440         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4441         for (p = 0; p < 2; ++p) {
4442           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);
4443         }
4444 #endif
4445         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4446         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4447         for (s = 0; s < supportSize; ++s) {
4448           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4449           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4450           for (c = 0; c < coneSize; ++c) {
4451             if (cone[c] == f) break;
4452           }
4453           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4454         }
4455         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4456 #if 1
4457         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4458         for (p = 0; p < supportSize; ++p) {
4459           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);
4460         }
4461 #endif
4462       }
4463     }
4464     /* Interior faces have 2 vertices and 2 cells */
4465     for (c = cStart; c < cEnd; ++c) {
4466       const PetscInt *cone;
4467 
4468       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4469       for (r = 0; r < 3; ++r) {
4470         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4471         PetscInt       coneNew[2];
4472         PetscInt       supportNew[2];
4473 
4474         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4475         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4476         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4477 #if 1
4478         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4479         for (p = 0; p < 2; ++p) {
4480           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);
4481         }
4482 #endif
4483         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4484         supportNew[1] = (c - cStart)*4 + 3;
4485         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4486 #if 1
4487         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4488         for (p = 0; p < 2; ++p) {
4489           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);
4490         }
4491 #endif
4492       }
4493     }
4494     /* Old vertices have identical supports */
4495     for (v = vStart; v < vEnd; ++v) {
4496       const PetscInt  newp = vStartNew + (v - vStart);
4497       const PetscInt *support, *cone;
4498       PetscInt        size, s;
4499 
4500       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4501       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4502       for (s = 0; s < size; ++s) {
4503         PetscInt r = 0;
4504 
4505         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4506         if (cone[1] == v) r = 1;
4507         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4508       }
4509       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4510 #if 1
4511       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4512       for (p = 0; p < size; ++p) {
4513         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);
4514       }
4515 #endif
4516     }
4517     /* Face vertices have 2 + cells*2 supports */
4518     for (f = fStart; f < fEnd; ++f) {
4519       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4520       const PetscInt *cone, *support;
4521       PetscInt        size, s;
4522 
4523       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4524       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4525       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4526       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4527       for (s = 0; s < size; ++s) {
4528         PetscInt r = 0;
4529 
4530         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4531         if      (cone[1] == f) r = 1;
4532         else if (cone[2] == f) r = 2;
4533         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4534         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
4535       }
4536       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4537 #if 1
4538       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4539       for (p = 0; p < 2+size*2; ++p) {
4540         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);
4541       }
4542 #endif
4543     }
4544     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4545     break;
4546   case 2:
4547     /* Hex 2D */
4548     /*
4549      3---------2---------2
4550      |         |         |
4551      |    D    2    C    |
4552      |         |         |
4553      3----3----0----1----1
4554      |         |         |
4555      |    A    0    B    |
4556      |         |         |
4557      0---------0---------1
4558      */
4559     /* All cells have 4 faces */
4560     for (c = cStart; c < cEnd; ++c) {
4561       const PetscInt  newp = (c - cStart)*4;
4562       const PetscInt *cone, *ornt;
4563       PetscInt        coneNew[4], orntNew[4];
4564 
4565       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4566       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4567       /* A quad */
4568       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4569       orntNew[0] = ornt[0];
4570       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4571       orntNew[1] = 0;
4572       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4573       orntNew[2] = -2;
4574       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
4575       orntNew[3] = ornt[3];
4576       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4577       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4578 #if 1
4579       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);
4580       for (p = 0; p < 4; ++p) {
4581         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);
4582       }
4583 #endif
4584       /* B quad */
4585       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4586       orntNew[0] = ornt[0];
4587       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4588       orntNew[1] = ornt[1];
4589       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4590       orntNew[2] = 0;
4591       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4592       orntNew[3] = -2;
4593       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4594       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4595 #if 1
4596       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);
4597       for (p = 0; p < 4; ++p) {
4598         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);
4599       }
4600 #endif
4601       /* C quad */
4602       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4603       orntNew[0] = -2;
4604       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4605       orntNew[1] = ornt[1];
4606       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4607       orntNew[2] = ornt[2];
4608       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4609       orntNew[3] = 0;
4610       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4611       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4612 #if 1
4613       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);
4614       for (p = 0; p < 4; ++p) {
4615         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);
4616       }
4617 #endif
4618       /* D quad */
4619       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4620       orntNew[0] = 0;
4621       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4622       orntNew[1] = -2;
4623       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4624       orntNew[2] = ornt[2];
4625       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
4626       orntNew[3] = ornt[3];
4627       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4628       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4629 #if 1
4630       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);
4631       for (p = 0; p < 4; ++p) {
4632         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);
4633       }
4634 #endif
4635     }
4636     /* Split faces have 2 vertices and the same cells as the parent */
4637     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4638     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4639     for (f = fStart; f < fEnd; ++f) {
4640       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4641 
4642       for (r = 0; r < 2; ++r) {
4643         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4644         const PetscInt *cone, *support;
4645         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4646 
4647         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4648         coneNew[0]       = vStartNew + (cone[0] - vStart);
4649         coneNew[1]       = vStartNew + (cone[1] - vStart);
4650         coneNew[(r+1)%2] = newv;
4651         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4652 #if 1
4653         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4654         for (p = 0; p < 2; ++p) {
4655           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);
4656         }
4657 #endif
4658         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4659         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4660         for (s = 0; s < supportSize; ++s) {
4661           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4662           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4663           for (c = 0; c < coneSize; ++c) {
4664             if (cone[c] == f) break;
4665           }
4666           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
4667         }
4668         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4669 #if 1
4670         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4671         for (p = 0; p < supportSize; ++p) {
4672           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);
4673         }
4674 #endif
4675       }
4676     }
4677     /* Interior faces have 2 vertices and 2 cells */
4678     for (c = cStart; c < cEnd; ++c) {
4679       const PetscInt *cone;
4680       PetscInt        coneNew[2], supportNew[2];
4681 
4682       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4683       for (r = 0; r < 4; ++r) {
4684         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4685 
4686         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
4687         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
4688         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4689 #if 1
4690         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4691         for (p = 0; p < 2; ++p) {
4692           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);
4693         }
4694 #endif
4695         supportNew[0] = (c - cStart)*4 + r;
4696         supportNew[1] = (c - cStart)*4 + (r+1)%4;
4697         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4698 #if 1
4699         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4700         for (p = 0; p < 2; ++p) {
4701           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);
4702         }
4703 #endif
4704       }
4705     }
4706     /* Old vertices have identical supports */
4707     for (v = vStart; v < vEnd; ++v) {
4708       const PetscInt  newp = vStartNew + (v - vStart);
4709       const PetscInt *support, *cone;
4710       PetscInt        size, s;
4711 
4712       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4713       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4714       for (s = 0; s < size; ++s) {
4715         PetscInt r = 0;
4716 
4717         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4718         if (cone[1] == v) r = 1;
4719         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4720       }
4721       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4722 #if 1
4723       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4724       for (p = 0; p < size; ++p) {
4725         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);
4726       }
4727 #endif
4728     }
4729     /* Face vertices have 2 + cells supports */
4730     for (f = fStart; f < fEnd; ++f) {
4731       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4732       const PetscInt *cone, *support;
4733       PetscInt        size, s;
4734 
4735       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4736       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4737       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4738       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4739       for (s = 0; s < size; ++s) {
4740         PetscInt r = 0;
4741 
4742         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4743         if      (cone[1] == f) r = 1;
4744         else if (cone[2] == f) r = 2;
4745         else if (cone[3] == f) r = 3;
4746         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
4747       }
4748       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4749 #if 1
4750       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4751       for (p = 0; p < 2+size; ++p) {
4752         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);
4753       }
4754 #endif
4755     }
4756     /* Cell vertices have 4 supports */
4757     for (c = cStart; c < cEnd; ++c) {
4758       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4759       PetscInt       supportNew[4];
4760 
4761       for (r = 0; r < 4; ++r) {
4762         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4763       }
4764       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4765     }
4766     break;
4767   case 3:
4768     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4769     cMax = PetscMin(cEnd, cMax);
4770     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4771     fMax = PetscMin(fEnd, fMax);
4772     /* Interior cells have 3 faces */
4773     for (c = cStart; c < cMax; ++c) {
4774       const PetscInt  newp = cStartNew + (c - cStart)*4;
4775       const PetscInt *cone, *ornt;
4776       PetscInt        coneNew[3], orntNew[3];
4777 
4778       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4779       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4780       /* A triangle */
4781       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4782       orntNew[0] = ornt[0];
4783       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4784       orntNew[1] = -2;
4785       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4786       orntNew[2] = ornt[2];
4787       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4788       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4789 #if 1
4790       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);
4791       for (p = 0; p < 3; ++p) {
4792         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);
4793       }
4794 #endif
4795       /* B triangle */
4796       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4797       orntNew[0] = ornt[0];
4798       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4799       orntNew[1] = ornt[1];
4800       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4801       orntNew[2] = -2;
4802       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4803       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4804 #if 1
4805       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);
4806       for (p = 0; p < 3; ++p) {
4807         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);
4808       }
4809 #endif
4810       /* C triangle */
4811       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4812       orntNew[0] = -2;
4813       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4814       orntNew[1] = ornt[1];
4815       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4816       orntNew[2] = ornt[2];
4817       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4818       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4819 #if 1
4820       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);
4821       for (p = 0; p < 3; ++p) {
4822         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);
4823       }
4824 #endif
4825       /* D triangle */
4826       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4827       orntNew[0] = 0;
4828       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4829       orntNew[1] = 0;
4830       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4831       orntNew[2] = 0;
4832       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4833       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4834 #if 1
4835       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);
4836       for (p = 0; p < 3; ++p) {
4837         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);
4838       }
4839 #endif
4840     }
4841     /*
4842      2----3----3
4843      |         |
4844      |    B    |
4845      |         |
4846      0----4--- 1
4847      |         |
4848      |    A    |
4849      |         |
4850      0----2----1
4851      */
4852     /* Hybrid cells have 4 faces */
4853     for (c = cMax; c < cEnd; ++c) {
4854       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
4855       const PetscInt *cone, *ornt;
4856       PetscInt        coneNew[4], orntNew[4];
4857 
4858       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4859       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4860       /* A quad */
4861       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4862       orntNew[0] = ornt[0];
4863       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4864       orntNew[1] = ornt[1];
4865       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
4866       orntNew[2] = 0;
4867       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4868       orntNew[3] = 0;
4869       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4870       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4871 #if 1
4872       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);
4873       for (p = 0; p < 4; ++p) {
4874         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);
4875       }
4876 #endif
4877       /* B quad */
4878       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4879       orntNew[0] = ornt[0];
4880       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4881       orntNew[1] = ornt[1];
4882       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4883       orntNew[2] = 0;
4884       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
4885       orntNew[3] = 0;
4886       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4887       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4888 #if 1
4889       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);
4890       for (p = 0; p < 4; ++p) {
4891         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);
4892       }
4893 #endif
4894     }
4895     /* Interior split faces have 2 vertices and the same cells as the parent */
4896     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4897     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4898     for (f = fStart; f < fMax; ++f) {
4899       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4900 
4901       for (r = 0; r < 2; ++r) {
4902         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4903         const PetscInt *cone, *support;
4904         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4905 
4906         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4907         coneNew[0]       = vStartNew + (cone[0] - vStart);
4908         coneNew[1]       = vStartNew + (cone[1] - vStart);
4909         coneNew[(r+1)%2] = newv;
4910         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4911 #if 1
4912         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4913         for (p = 0; p < 2; ++p) {
4914           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);
4915         }
4916 #endif
4917         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4918         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4919         for (s = 0; s < supportSize; ++s) {
4920           if (support[s] >= cMax) {
4921             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4922           } else {
4923             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4924             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4925             for (c = 0; c < coneSize; ++c) {
4926               if (cone[c] == f) break;
4927             }
4928             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4929           }
4930         }
4931         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4932 #if 1
4933         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4934         for (p = 0; p < supportSize; ++p) {
4935           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);
4936         }
4937 #endif
4938       }
4939     }
4940     /* Interior cell faces have 2 vertices and 2 cells */
4941     for (c = cStart; c < cMax; ++c) {
4942       const PetscInt *cone;
4943 
4944       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4945       for (r = 0; r < 3; ++r) {
4946         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4947         PetscInt       coneNew[2];
4948         PetscInt       supportNew[2];
4949 
4950         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4951         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4952         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4953 #if 1
4954         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4955         for (p = 0; p < 2; ++p) {
4956           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);
4957         }
4958 #endif
4959         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4960         supportNew[1] = (c - cStart)*4 + 3;
4961         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4962 #if 1
4963         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4964         for (p = 0; p < 2; ++p) {
4965           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);
4966         }
4967 #endif
4968       }
4969     }
4970     /* Interior hybrid faces have 2 vertices and the same cells */
4971     for (f = fMax; f < fEnd; ++f) {
4972       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4973       const PetscInt *cone;
4974       const PetscInt *support;
4975       PetscInt        coneNew[2];
4976       PetscInt        supportNew[2];
4977       PetscInt        size, s, r;
4978 
4979       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4980       coneNew[0] = vStartNew + (cone[0] - vStart);
4981       coneNew[1] = vStartNew + (cone[1] - vStart);
4982       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4983 #if 1
4984       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4985       for (p = 0; p < 2; ++p) {
4986         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);
4987       }
4988 #endif
4989       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4990       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4991       for (s = 0; s < size; ++s) {
4992         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4993         for (r = 0; r < 2; ++r) {
4994           if (cone[r+2] == f) break;
4995         }
4996         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4997       }
4998       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4999 #if 1
5000       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5001       for (p = 0; p < size; ++p) {
5002         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);
5003       }
5004 #endif
5005     }
5006     /* Cell hybrid faces have 2 vertices and 2 cells */
5007     for (c = cMax; c < cEnd; ++c) {
5008       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5009       const PetscInt *cone;
5010       PetscInt        coneNew[2];
5011       PetscInt        supportNew[2];
5012 
5013       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5014       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
5015       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
5016       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5017 #if 1
5018       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5019       for (p = 0; p < 2; ++p) {
5020         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);
5021       }
5022 #endif
5023       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
5024       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
5025       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5026 #if 1
5027       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5028       for (p = 0; p < 2; ++p) {
5029         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);
5030       }
5031 #endif
5032     }
5033     /* Old vertices have identical supports */
5034     for (v = vStart; v < vEnd; ++v) {
5035       const PetscInt  newp = vStartNew + (v - vStart);
5036       const PetscInt *support, *cone;
5037       PetscInt        size, s;
5038 
5039       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5040       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5041       for (s = 0; s < size; ++s) {
5042         if (support[s] >= fMax) {
5043           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
5044         } else {
5045           PetscInt r = 0;
5046 
5047           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5048           if (cone[1] == v) r = 1;
5049           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5050         }
5051       }
5052       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5053 #if 1
5054       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5055       for (p = 0; p < size; ++p) {
5056         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);
5057       }
5058 #endif
5059     }
5060     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5061     for (f = fStart; f < fMax; ++f) {
5062       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5063       const PetscInt *cone, *support;
5064       PetscInt        size, newSize = 2, s;
5065 
5066       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5067       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5068       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5069       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5070       for (s = 0; s < size; ++s) {
5071         PetscInt r = 0;
5072 
5073         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5074         if (support[s] >= cMax) {
5075           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
5076 
5077           newSize += 1;
5078         } else {
5079           if      (cone[1] == f) r = 1;
5080           else if (cone[2] == f) r = 2;
5081           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5082           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
5083 
5084           newSize += 2;
5085         }
5086       }
5087       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5088 #if 1
5089       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5090       for (p = 0; p < newSize; ++p) {
5091         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);
5092       }
5093 #endif
5094     }
5095     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5096     break;
5097   default:
5098     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5099   }
5100   PetscFunctionReturn(0);
5101 }
5102 
5103 #undef __FUNCT__
5104 #define __FUNCT__ "CellRefinerSetCoordinates"
5105 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5106 {
5107   PetscSection   coordSection, coordSectionNew;
5108   Vec            coordinates, coordinatesNew;
5109   PetscScalar   *coords, *coordsNew;
5110   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
5111   PetscErrorCode ierr;
5112 
5113   PetscFunctionBegin;
5114   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5115   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5116   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5117   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5118   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5119   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
5120   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5121   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5122   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5123   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5124   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5125   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
5126   if (fMax < 0) fMax = fEnd;
5127   switch (refiner) {
5128   case 1:
5129   case 2:
5130   case 3:
5131     /* Simplicial and Hex 2D */
5132     /* All vertices have the dim coordinates */
5133     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5134       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5135       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5136     }
5137     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5138     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5139     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5140     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5141     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5142     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5143     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5144     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5145     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5146     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5147     /* Old vertices have the same coordinates */
5148     for (v = vStart; v < vEnd; ++v) {
5149       const PetscInt newv = vStartNew + (v - vStart);
5150       PetscInt       off, offnew, d;
5151 
5152       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5153       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5154       for (d = 0; d < dim; ++d) {
5155         coordsNew[offnew+d] = coords[off+d];
5156       }
5157     }
5158     /* Face vertices have the average of endpoint coordinates */
5159     for (f = fStart; f < fMax; ++f) {
5160       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5161       const PetscInt *cone;
5162       PetscInt        coneSize, offA, offB, offnew, d;
5163 
5164       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5165       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5166       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5167       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5168       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5169       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5170       for (d = 0; d < dim; ++d) {
5171         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5172       }
5173     }
5174     /* Just Hex 2D */
5175     if (refiner == 2) {
5176       /* Cell vertices have the average of corner coordinates */
5177       for (c = cStart; c < cEnd; ++c) {
5178         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5179         PetscInt      *cone = NULL;
5180         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5181 
5182         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5183         for (p = 0; p < closureSize*2; p += 2) {
5184           const PetscInt point = cone[p];
5185           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5186         }
5187         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5188         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5189         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5190         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5191         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5192         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5193         for (d = 0; d < dim; ++d) {
5194           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5195         }
5196         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5197       }
5198     }
5199     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5200     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5201     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5202     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5203     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5204     break;
5205   default:
5206     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5207   }
5208   PetscFunctionReturn(0);
5209 }
5210 
5211 #undef __FUNCT__
5212 #define __FUNCT__ "DMPlexCreateProcessSF"
5213 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5214 {
5215   PetscInt           numRoots, numLeaves, l;
5216   const PetscInt    *localPoints;
5217   const PetscSFNode *remotePoints;
5218   PetscInt          *localPointsNew;
5219   PetscSFNode       *remotePointsNew;
5220   PetscInt          *ranks, *ranksNew;
5221   PetscErrorCode     ierr;
5222 
5223   PetscFunctionBegin;
5224   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5225   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5226   for (l = 0; l < numLeaves; ++l) {
5227     ranks[l] = remotePoints[l].rank;
5228   }
5229   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5230   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
5231   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5232   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5233   for (l = 0; l < numLeaves; ++l) {
5234     ranksNew[l]              = ranks[l];
5235     localPointsNew[l]        = l;
5236     remotePointsNew[l].index = 0;
5237     remotePointsNew[l].rank  = ranksNew[l];
5238   }
5239   ierr = PetscFree(ranks);CHKERRQ(ierr);
5240   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5241   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5242   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5243   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5244   PetscFunctionReturn(0);
5245 }
5246 
5247 #undef __FUNCT__
5248 #define __FUNCT__ "CellRefinerCreateSF"
5249 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5250 {
5251   PetscSF            sf, sfNew, sfProcess;
5252   IS                 processRanks;
5253   MPI_Datatype       depthType;
5254   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5255   const PetscInt    *localPoints, *neighbors;
5256   const PetscSFNode *remotePoints;
5257   PetscInt          *localPointsNew;
5258   PetscSFNode       *remotePointsNew;
5259   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5260   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
5261   PetscErrorCode     ierr;
5262 
5263   PetscFunctionBegin;
5264   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5265   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5266   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5267   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5268   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5269   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5270   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5271   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5272   switch (refiner) {
5273   case 3:
5274     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5275     cMax = PetscMin(cEnd, cMax);
5276     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5277     fMax = PetscMin(fEnd, fMax);
5278   }
5279   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5280   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5281   /* Caculate size of new SF */
5282   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5283   if (numRoots < 0) PetscFunctionReturn(0);
5284   for (l = 0; l < numLeaves; ++l) {
5285     const PetscInt p = localPoints[l];
5286 
5287     switch (refiner) {
5288     case 1:
5289       /* Simplicial 2D */
5290       if ((p >= vStart) && (p < vEnd)) {
5291         /* Old vertices stay the same */
5292         ++numLeavesNew;
5293       } else if ((p >= fStart) && (p < fEnd)) {
5294         /* Old faces add new faces and vertex */
5295         numLeavesNew += 1 + 2;
5296       } else if ((p >= cStart) && (p < cEnd)) {
5297         /* Old cells add new cells and interior faces */
5298         numLeavesNew += 4 + 3;
5299       }
5300       break;
5301     case 2:
5302       /* Hex 2D */
5303       if ((p >= vStart) && (p < vEnd)) {
5304         /* Old vertices stay the same */
5305         ++numLeavesNew;
5306       } else if ((p >= fStart) && (p < fEnd)) {
5307         /* Old faces add new faces and vertex */
5308         numLeavesNew += 1 + 2;
5309       } else if ((p >= cStart) && (p < cEnd)) {
5310         /* Old cells add new cells and interior faces */
5311         numLeavesNew += 4 + 4;
5312       }
5313       break;
5314     default:
5315       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5316     }
5317   }
5318   /* Communicate depthSizes for each remote rank */
5319   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5320   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5321   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
5322   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);
5323   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5324   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5325   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5326   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5327   for (n = 0; n < numNeighbors; ++n) {
5328     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5329   }
5330   depthSizeOld[depth]   = cMax;
5331   depthSizeOld[0]       = vMax;
5332   depthSizeOld[depth-1] = fMax;
5333   depthSizeOld[1]       = eMax;
5334 
5335   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5336   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5337 
5338   depthSizeOld[depth]   = cEnd - cStart;
5339   depthSizeOld[0]       = vEnd - vStart;
5340   depthSizeOld[depth-1] = fEnd - fStart;
5341   depthSizeOld[1]       = eEnd - eStart;
5342 
5343   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5344   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5345   for (n = 0; n < numNeighbors; ++n) {
5346     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5347   }
5348   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5349   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5350   /* Calculate new point SF */
5351   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5352   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5353   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5354   for (l = 0, m = 0; l < numLeaves; ++l) {
5355     PetscInt    p     = localPoints[l];
5356     PetscInt    rp    = remotePoints[l].index, n;
5357     PetscMPIInt rrank = remotePoints[l].rank;
5358 
5359     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5360     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5361     switch (refiner) {
5362     case 1:
5363       /* Simplicial 2D */
5364       if ((p >= vStart) && (p < vEnd)) {
5365         /* Old vertices stay the same */
5366         localPointsNew[m]        = vStartNew     + (p  - vStart);
5367         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5368         remotePointsNew[m].rank  = rrank;
5369         ++m;
5370       } else if ((p >= fStart) && (p < fEnd)) {
5371         /* Old faces add new faces and vertex */
5372         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5373         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5374         remotePointsNew[m].rank  = rrank;
5375         ++m;
5376         for (r = 0; r < 2; ++r, ++m) {
5377           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5378           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5379           remotePointsNew[m].rank  = rrank;
5380         }
5381       } else if ((p >= cStart) && (p < cEnd)) {
5382         /* Old cells add new cells and interior faces */
5383         for (r = 0; r < 4; ++r, ++m) {
5384           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5385           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5386           remotePointsNew[m].rank  = rrank;
5387         }
5388         for (r = 0; r < 3; ++r, ++m) {
5389           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5390           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5391           remotePointsNew[m].rank  = rrank;
5392         }
5393       }
5394       break;
5395     case 2:
5396       /* Hex 2D */
5397       if ((p >= vStart) && (p < vEnd)) {
5398         /* Old vertices stay the same */
5399         localPointsNew[m]        = vStartNew     + (p  - vStart);
5400         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5401         remotePointsNew[m].rank  = rrank;
5402         ++m;
5403       } else if ((p >= fStart) && (p < fEnd)) {
5404         /* Old faces add new faces and vertex */
5405         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5406         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5407         remotePointsNew[m].rank  = rrank;
5408         ++m;
5409         for (r = 0; r < 2; ++r, ++m) {
5410           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5411           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5412           remotePointsNew[m].rank  = rrank;
5413         }
5414       } else if ((p >= cStart) && (p < cEnd)) {
5415         /* Old cells add new cells and interior faces */
5416         for (r = 0; r < 4; ++r, ++m) {
5417           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5418           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5419           remotePointsNew[m].rank  = rrank;
5420         }
5421         for (r = 0; r < 4; ++r, ++m) {
5422           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5423           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5424           remotePointsNew[m].rank  = rrank;
5425         }
5426       }
5427       break;
5428     case 3:
5429       /* Hybrid simplicial 2D */
5430       if ((p >= vStart) && (p < vEnd)) {
5431         /* Old vertices stay the same */
5432         localPointsNew[m]        = vStartNew     + (p  - vStart);
5433         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5434         remotePointsNew[m].rank  = rrank;
5435         ++m;
5436       } else if ((p >= fStart) && (p < fMax)) {
5437         /* Old interior faces add new faces and vertex */
5438         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5439         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5440         remotePointsNew[m].rank  = rrank;
5441         ++m;
5442         for (r = 0; r < 2; ++r, ++m) {
5443           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5444           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5445           remotePointsNew[m].rank  = rrank;
5446         }
5447       } else if ((p >= fMax) && (p < fEnd)) {
5448         /* Old hybrid faces stay the same */
5449         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5450         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5451         remotePointsNew[m].rank  = rrank;
5452         ++m;
5453       } else if ((p >= cStart) && (p < cMax)) {
5454         /* Old interior cells add new cells and interior faces */
5455         for (r = 0; r < 4; ++r, ++m) {
5456           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5457           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5458           remotePointsNew[m].rank  = rrank;
5459         }
5460         for (r = 0; r < 3; ++r, ++m) {
5461           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5462           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5463           remotePointsNew[m].rank  = rrank;
5464         }
5465       } else if ((p >= cStart) && (p < cMax)) {
5466         /* Old hybrid cells add new cells and hybrid face */
5467         for (r = 0; r < 2; ++r, ++m) {
5468           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5469           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5470           remotePointsNew[m].rank  = rrank;
5471         }
5472         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5473         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]);
5474         remotePointsNew[m].rank  = rrank;
5475         ++m;
5476       }
5477       break;
5478     default:
5479       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5480     }
5481   }
5482   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5483   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5484   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5485   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5486   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5487   PetscFunctionReturn(0);
5488 }
5489 
5490 #undef __FUNCT__
5491 #define __FUNCT__ "CellRefinerCreateLabels"
5492 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5493 {
5494   PetscInt       numLabels, l;
5495   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
5496   PetscErrorCode ierr;
5497 
5498   PetscFunctionBegin;
5499   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5500   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5501   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5502   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5503 
5504   cStartNew = 0;
5505   vStartNew = depthSize[2];
5506   fStartNew = depthSize[2] + depthSize[0];
5507 
5508   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5509   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5510   switch (refiner) {
5511   case 3:
5512     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5513     cMax = PetscMin(cEnd, cMax);
5514     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5515     fMax = PetscMin(fEnd, fMax);
5516   }
5517   for (l = 0; l < numLabels; ++l) {
5518     DMLabel         label, labelNew;
5519     const char     *lname;
5520     PetscBool       isDepth;
5521     IS              valueIS;
5522     const PetscInt *values;
5523     PetscInt        numValues, val;
5524 
5525     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5526     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5527     if (isDepth) continue;
5528     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5529     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5530     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5531     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5532     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5533     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5534     for (val = 0; val < numValues; ++val) {
5535       IS              pointIS;
5536       const PetscInt *points;
5537       PetscInt        numPoints, n;
5538 
5539       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5540       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5541       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5542       for (n = 0; n < numPoints; ++n) {
5543         const PetscInt p = points[n];
5544         switch (refiner) {
5545         case 1:
5546           /* Simplicial 2D */
5547           if ((p >= vStart) && (p < vEnd)) {
5548             /* Old vertices stay the same */
5549             newp = vStartNew + (p - vStart);
5550             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5551           } else if ((p >= fStart) && (p < fEnd)) {
5552             /* Old faces add new faces and vertex */
5553             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5554             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5555             for (r = 0; r < 2; ++r) {
5556               newp = fStartNew + (p - fStart)*2 + r;
5557               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5558             }
5559           } else if ((p >= cStart) && (p < cEnd)) {
5560             /* Old cells add new cells and interior faces */
5561             for (r = 0; r < 4; ++r) {
5562               newp = cStartNew + (p - cStart)*4 + r;
5563               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5564             }
5565             for (r = 0; r < 3; ++r) {
5566               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5567               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5568             }
5569           }
5570           break;
5571         case 2:
5572           /* Hex 2D */
5573           if ((p >= vStart) && (p < vEnd)) {
5574             /* Old vertices stay the same */
5575             newp = vStartNew + (p - vStart);
5576             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5577           } else if ((p >= fStart) && (p < fEnd)) {
5578             /* Old faces add new faces and vertex */
5579             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5580             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5581             for (r = 0; r < 2; ++r) {
5582               newp = fStartNew + (p - fStart)*2 + r;
5583               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5584             }
5585           } else if ((p >= cStart) && (p < cEnd)) {
5586             /* Old cells add new cells and interior faces and vertex */
5587             for (r = 0; r < 4; ++r) {
5588               newp = cStartNew + (p - cStart)*4 + r;
5589               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5590             }
5591             for (r = 0; r < 4; ++r) {
5592               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5593               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5594             }
5595             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5596             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5597           }
5598           break;
5599         case 3:
5600           /* Hybrid simplicial 2D */
5601           if ((p >= vStart) && (p < vEnd)) {
5602             /* Old vertices stay the same */
5603             newp = vStartNew + (p - vStart);
5604             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5605           } else if ((p >= fStart) && (p < fMax)) {
5606             /* Old interior faces add new faces and vertex */
5607             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5608             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5609             for (r = 0; r < 2; ++r) {
5610               newp = fStartNew + (p - fStart)*2 + r;
5611               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5612             }
5613           } else if ((p >= fMax) && (p < fEnd)) {
5614             /* Old hybrid faces stay the same */
5615             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5616             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5617           } else if ((p >= cStart) && (p < cMax)) {
5618             /* Old interior cells add new cells and interior faces */
5619             for (r = 0; r < 4; ++r) {
5620               newp = cStartNew + (p - cStart)*4 + r;
5621               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5622             }
5623             for (r = 0; r < 3; ++r) {
5624               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5625               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5626             }
5627           } else if ((p >= cMax) && (p < cEnd)) {
5628             /* Old hybrid cells add new cells and hybrid face */
5629             for (r = 0; r < 2; ++r) {
5630               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5631               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5632             }
5633             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5634             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5635           }
5636           break;
5637         default:
5638           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5639         }
5640       }
5641       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
5642       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5643     }
5644     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
5645     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
5646     if (0) {
5647       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
5648       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5649       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5650     }
5651   }
5652   PetscFunctionReturn(0);
5653 }
5654 
5655 #undef __FUNCT__
5656 #define __FUNCT__ "DMPlexRefine_Uniform"
5657 /* This will only work for interpolated meshes */
5658 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
5659 {
5660   DM             rdm;
5661   PetscInt      *depthSize;
5662   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
5663   PetscErrorCode ierr;
5664 
5665   PetscFunctionBegin;
5666   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
5667   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
5668   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5669   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
5670   /* Calculate number of new points of each depth */
5671   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5672   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
5673   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
5674   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
5675   /* Step 1: Set chart */
5676   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
5677   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
5678   /* Step 2: Set cone/support sizes */
5679   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5680   /* Step 3: Setup refined DM */
5681   ierr = DMSetUp(rdm);CHKERRQ(ierr);
5682   /* Step 4: Set cones and supports */
5683   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5684   /* Step 5: Stratify */
5685   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
5686   /* Step 6: Set coordinates for vertices */
5687   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5688   /* Step 7: Create pointSF */
5689   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5690   /* Step 8: Create labels */
5691   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5692   ierr = PetscFree(depthSize);CHKERRQ(ierr);
5693 
5694   *dmRefined = rdm;
5695   PetscFunctionReturn(0);
5696 }
5697 
5698 #undef __FUNCT__
5699 #define __FUNCT__ "DMPlexSetRefinementUniform"
5700 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
5701 {
5702   DM_Plex *mesh = (DM_Plex*) dm->data;
5703 
5704   PetscFunctionBegin;
5705   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5706   mesh->refinementUniform = refinementUniform;
5707   PetscFunctionReturn(0);
5708 }
5709 
5710 #undef __FUNCT__
5711 #define __FUNCT__ "DMPlexGetRefinementUniform"
5712 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
5713 {
5714   DM_Plex *mesh = (DM_Plex*) dm->data;
5715 
5716   PetscFunctionBegin;
5717   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5718   PetscValidPointer(refinementUniform,  2);
5719   *refinementUniform = mesh->refinementUniform;
5720   PetscFunctionReturn(0);
5721 }
5722 
5723 #undef __FUNCT__
5724 #define __FUNCT__ "DMPlexSetRefinementLimit"
5725 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
5726 {
5727   DM_Plex *mesh = (DM_Plex*) dm->data;
5728 
5729   PetscFunctionBegin;
5730   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5731   mesh->refinementLimit = refinementLimit;
5732   PetscFunctionReturn(0);
5733 }
5734 
5735 #undef __FUNCT__
5736 #define __FUNCT__ "DMPlexGetRefinementLimit"
5737 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
5738 {
5739   DM_Plex *mesh = (DM_Plex*) dm->data;
5740 
5741   PetscFunctionBegin;
5742   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5743   PetscValidPointer(refinementLimit,  2);
5744   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
5745   *refinementLimit = mesh->refinementLimit;
5746   PetscFunctionReturn(0);
5747 }
5748 
5749 #undef __FUNCT__
5750 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
5751 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
5752 {
5753   PetscInt       dim, cStart, coneSize, cMax;
5754   PetscErrorCode ierr;
5755 
5756   PetscFunctionBegin;
5757   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5758   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
5759   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
5760   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5761   switch (dim) {
5762   case 2:
5763     switch (coneSize) {
5764     case 3:
5765       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
5766       else *cellRefiner = 1; /* Triangular */
5767       break;
5768     case 4:
5769       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
5770       else *cellRefiner = 2; /* Quadrilateral */
5771       break;
5772     default:
5773       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
5774     }
5775     break;
5776   default:
5777     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
5778   }
5779   PetscFunctionReturn(0);
5780 }
5781 
5782 #undef __FUNCT__
5783 #define __FUNCT__ "DMRefine_Plex"
5784 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
5785 {
5786   PetscReal      refinementLimit;
5787   PetscInt       dim, cStart, cEnd;
5788   char           genname[1024], *name = NULL;
5789   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5790   PetscErrorCode ierr;
5791 
5792   PetscFunctionBegin;
5793   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
5794   if (isUniform) {
5795     CellRefiner cellRefiner;
5796 
5797     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
5798     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
5799     PetscFunctionReturn(0);
5800   }
5801   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
5802   if (refinementLimit == 0.0) PetscFunctionReturn(0);
5803   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5804   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5805   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5806   if (flg) name = genname;
5807   if (name) {
5808     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5809     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5810     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5811   }
5812   switch (dim) {
5813   case 2:
5814     if (!name || isTriangle) {
5815 #if defined(PETSC_HAVE_TRIANGLE)
5816       double  *maxVolumes;
5817       PetscInt c;
5818 
5819       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5820       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5821       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5822 #else
5823       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
5824 #endif
5825     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5826     break;
5827   case 3:
5828     if (!name || isCTetgen) {
5829 #if defined(PETSC_HAVE_CTETGEN)
5830       PetscReal *maxVolumes;
5831       PetscInt   c;
5832 
5833       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
5834       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5835       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5836 #else
5837       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5838 #endif
5839     } else if (isTetgen) {
5840 #if defined(PETSC_HAVE_TETGEN)
5841       double  *maxVolumes;
5842       PetscInt c;
5843 
5844       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5845       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5846       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5847 #else
5848       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5849 #endif
5850     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5851     break;
5852   default:
5853     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
5854   }
5855   PetscFunctionReturn(0);
5856 }
5857 
5858 #undef __FUNCT__
5859 #define __FUNCT__ "DMPlexGetDepth"
5860 /*@
5861   DMPlexGetDepth - get the number of strata
5862 
5863   Not Collective
5864 
5865   Input Parameters:
5866 . dm           - The DMPlex object
5867 
5868   Output Parameters:
5869 . depth - number of strata
5870 
5871   Level: developer
5872 
5873   Notes:
5874   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
5875 
5876 .keywords: mesh, points
5877 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
5878 @*/
5879 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5880 {
5881   PetscInt       d;
5882   PetscErrorCode ierr;
5883 
5884   PetscFunctionBegin;
5885   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5886   PetscValidPointer(depth, 2);
5887   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
5888   *depth = d-1;
5889   PetscFunctionReturn(0);
5890 }
5891 
5892 #undef __FUNCT__
5893 #define __FUNCT__ "DMPlexGetDepthStratum"
5894 /*@
5895   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
5896 
5897   Not Collective
5898 
5899   Input Parameters:
5900 + dm           - The DMPlex object
5901 - stratumValue - The requested depth
5902 
5903   Output Parameters:
5904 + start - The first point at this depth
5905 - end   - One beyond the last point at this depth
5906 
5907   Level: developer
5908 
5909 .keywords: mesh, points
5910 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
5911 @*/
5912 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5913 {
5914   DM_Plex       *mesh = (DM_Plex*) dm->data;
5915   DMLabel        next  = mesh->labels;
5916   PetscBool      flg   = PETSC_FALSE;
5917   PetscInt       depth;
5918   PetscErrorCode ierr;
5919 
5920   PetscFunctionBegin;
5921   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5922   if (stratumValue < 0) {
5923     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
5924     PetscFunctionReturn(0);
5925   } else {
5926     PetscInt pStart, pEnd;
5927 
5928     if (start) *start = 0;
5929     if (end)   *end   = 0;
5930     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5931     if (pStart == pEnd) PetscFunctionReturn(0);
5932   }
5933   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
5934   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
5935   /* We should have a generic GetLabel() and a Label class */
5936   while (next) {
5937     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
5938     if (flg) break;
5939     next = next->next;
5940   }
5941   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
5942   depth = stratumValue;
5943   if ((depth < 0) || (depth >= next->numStrata)) {
5944     if (start) *start = 0;
5945     if (end)   *end   = 0;
5946   } else {
5947     if (start) *start = next->points[next->stratumOffsets[depth]];
5948     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
5949   }
5950   PetscFunctionReturn(0);
5951 }
5952 
5953 #undef __FUNCT__
5954 #define __FUNCT__ "DMPlexGetHeightStratum"
5955 /*@
5956   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
5957 
5958   Not Collective
5959 
5960   Input Parameters:
5961 + dm           - The DMPlex object
5962 - stratumValue - The requested height
5963 
5964   Output Parameters:
5965 + start - The first point at this height
5966 - end   - One beyond the last point at this height
5967 
5968   Level: developer
5969 
5970 .keywords: mesh, points
5971 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
5972 @*/
5973 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5974 {
5975   DM_Plex       *mesh = (DM_Plex*) dm->data;
5976   DMLabel        next  = mesh->labels;
5977   PetscBool      flg   = PETSC_FALSE;
5978   PetscInt       depth;
5979   PetscErrorCode ierr;
5980 
5981   PetscFunctionBegin;
5982   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5983   if (stratumValue < 0) {
5984     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
5985   } else {
5986     PetscInt pStart, pEnd;
5987 
5988     if (start) *start = 0;
5989     if (end)   *end   = 0;
5990     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5991     if (pStart == pEnd) PetscFunctionReturn(0);
5992   }
5993   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
5994   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
5995   /* We should have a generic GetLabel() and a Label class */
5996   while (next) {
5997     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
5998     if (flg) break;
5999     next = next->next;
6000   }
6001   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6002   depth = next->stratumValues[next->numStrata-1] - stratumValue;
6003   if ((depth < 0) || (depth >= next->numStrata)) {
6004     if (start) *start = 0;
6005     if (end)   *end   = 0;
6006   } else {
6007     if (start) *start = next->points[next->stratumOffsets[depth]];
6008     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
6009   }
6010   PetscFunctionReturn(0);
6011 }
6012 
6013 #undef __FUNCT__
6014 #define __FUNCT__ "DMPlexCreateSectionInitial"
6015 /* Set the number of dof on each point and separate by fields */
6016 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
6017 {
6018   PetscInt      *numDofTot;
6019   PetscInt       pStart = 0, pEnd = 0;
6020   PetscInt       p, d, f;
6021   PetscErrorCode ierr;
6022 
6023   PetscFunctionBegin;
6024   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
6025   for (d = 0; d <= dim; ++d) {
6026     numDofTot[d] = 0;
6027     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
6028   }
6029   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
6030   if (numFields > 0) {
6031     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
6032     if (numComp) {
6033       for (f = 0; f < numFields; ++f) {
6034         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
6035       }
6036     }
6037   }
6038   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6039   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
6040   for (d = 0; d <= dim; ++d) {
6041     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
6042     for (p = pStart; p < pEnd; ++p) {
6043       for (f = 0; f < numFields; ++f) {
6044         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
6045       }
6046       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
6047     }
6048   }
6049   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
6050   PetscFunctionReturn(0);
6051 }
6052 
6053 #undef __FUNCT__
6054 #define __FUNCT__ "DMPlexCreateSectionBCDof"
6055 /* Set the number of dof on each point and separate by fields
6056    If constDof is PETSC_DETERMINE, constrain every dof on the point
6057 */
6058 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
6059 {
6060   PetscInt       numFields;
6061   PetscInt       bc;
6062   PetscErrorCode ierr;
6063 
6064   PetscFunctionBegin;
6065   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6066   for (bc = 0; bc < numBC; ++bc) {
6067     PetscInt        field = 0;
6068     const PetscInt *idx;
6069     PetscInt        n, i;
6070 
6071     if (numFields) field = bcField[bc];
6072     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
6073     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6074     for (i = 0; i < n; ++i) {
6075       const PetscInt p        = idx[i];
6076       PetscInt       numConst = constDof;
6077 
6078       /* Constrain every dof on the point */
6079       if (numConst < 0) {
6080         if (numFields) {
6081           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
6082         } else {
6083           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
6084         }
6085       }
6086       if (numFields) {
6087         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
6088       }
6089       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
6090     }
6091     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6092   }
6093   PetscFunctionReturn(0);
6094 }
6095 
6096 #undef __FUNCT__
6097 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
6098 /* Set the constrained indices on each point and separate by fields */
6099 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
6100 {
6101   PetscInt      *maxConstraints;
6102   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
6103   PetscErrorCode ierr;
6104 
6105   PetscFunctionBegin;
6106   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6107   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6108   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
6109   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
6110   for (p = pStart; p < pEnd; ++p) {
6111     PetscInt cdof;
6112 
6113     if (numFields) {
6114       for (f = 0; f < numFields; ++f) {
6115         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
6116         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
6117       }
6118     } else {
6119       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6120       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
6121     }
6122   }
6123   for (f = 0; f < numFields; ++f) {
6124     maxConstraints[numFields] += maxConstraints[f];
6125   }
6126   if (maxConstraints[numFields]) {
6127     PetscInt *indices;
6128 
6129     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6130     for (p = pStart; p < pEnd; ++p) {
6131       PetscInt cdof, d;
6132 
6133       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6134       if (cdof) {
6135         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
6136         if (numFields) {
6137           PetscInt numConst = 0, foff = 0;
6138 
6139           for (f = 0; f < numFields; ++f) {
6140             PetscInt cfdof, fdof;
6141 
6142             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6143             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
6144             /* Change constraint numbering from absolute local dof number to field relative local dof number */
6145             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
6146             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
6147             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
6148             numConst += cfdof;
6149             foff     += fdof;
6150           }
6151           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6152         } else {
6153           for (d = 0; d < cdof; ++d) indices[d] = d;
6154         }
6155         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6156       }
6157     }
6158     ierr = PetscFree(indices);CHKERRQ(ierr);
6159   }
6160   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
6161   PetscFunctionReturn(0);
6162 }
6163 
6164 #undef __FUNCT__
6165 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
6166 /* Set the constrained field indices on each point */
6167 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
6168 {
6169   const PetscInt *points, *indices;
6170   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
6171   PetscErrorCode  ierr;
6172 
6173   PetscFunctionBegin;
6174   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6175   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
6176 
6177   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
6178   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
6179   if (!constraintIndices) {
6180     PetscInt *idx, i;
6181 
6182     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6183     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
6184     for (i = 0; i < maxDof; ++i) idx[i] = i;
6185     for (p = 0; p < numPoints; ++p) {
6186       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
6187     }
6188     ierr = PetscFree(idx);CHKERRQ(ierr);
6189   } else {
6190     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
6191     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
6192     for (p = 0; p < numPoints; ++p) {
6193       PetscInt fcdof;
6194 
6195       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
6196       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);
6197       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
6198     }
6199     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
6200   }
6201   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
6202   PetscFunctionReturn(0);
6203 }
6204 
6205 #undef __FUNCT__
6206 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
6207 /* Set the constrained indices on each point and separate by fields */
6208 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
6209 {
6210   PetscInt      *indices;
6211   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
6212   PetscErrorCode ierr;
6213 
6214   PetscFunctionBegin;
6215   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6216   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6217   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6218   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
6219   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6220   for (p = pStart; p < pEnd; ++p) {
6221     PetscInt cdof, d;
6222 
6223     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6224     if (cdof) {
6225       PetscInt numConst = 0, foff = 0;
6226 
6227       for (f = 0; f < numFields; ++f) {
6228         const PetscInt *fcind;
6229         PetscInt        fdof, fcdof;
6230 
6231         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6232         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
6233         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
6234         /* Change constraint numbering from field relative local dof number to absolute local dof number */
6235         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
6236         foff     += fdof;
6237         numConst += fcdof;
6238       }
6239       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6240       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6241     }
6242   }
6243   ierr = PetscFree(indices);CHKERRQ(ierr);
6244   PetscFunctionReturn(0);
6245 }
6246 
6247 #undef __FUNCT__
6248 #define __FUNCT__ "DMPlexCreateSection"
6249 /*@C
6250   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
6251 
6252   Not Collective
6253 
6254   Input Parameters:
6255 + dm        - The DMPlex object
6256 . dim       - The spatial dimension of the problem
6257 . numFields - The number of fields in the problem
6258 . numComp   - An array of size numFields that holds the number of components for each field
6259 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
6260 . numBC     - The number of boundary conditions
6261 . bcField   - An array of size numBC giving the field number for each boundry condition
6262 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
6263 
6264   Output Parameter:
6265 . section - The PetscSection object
6266 
6267   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
6268   nubmer of dof for field 0 on each edge.
6269 
6270   Level: developer
6271 
6272   Fortran Notes:
6273   A Fortran 90 version is available as DMPlexCreateSectionF90()
6274 
6275 .keywords: mesh, elements
6276 .seealso: DMPlexCreate(), PetscSectionCreate()
6277 @*/
6278 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
6279 {
6280   PetscErrorCode ierr;
6281 
6282   PetscFunctionBegin;
6283   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
6284   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
6285   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
6286   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
6287   {
6288     PetscBool view = PETSC_FALSE;
6289 
6290     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
6291     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
6292   }
6293   PetscFunctionReturn(0);
6294 }
6295 
6296 #undef __FUNCT__
6297 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
6298 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
6299 {
6300   PetscSection   section;
6301   PetscErrorCode ierr;
6302 
6303   PetscFunctionBegin;
6304   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
6305   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6306   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
6307   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6308   PetscFunctionReturn(0);
6309 }
6310 
6311 #undef __FUNCT__
6312 #define __FUNCT__ "DMPlexGetCoordinateSection"
6313 /*@
6314   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6315 
6316   Not Collective
6317 
6318   Input Parameter:
6319 . dm - The DMPlex object
6320 
6321   Output Parameter:
6322 . section - The PetscSection object
6323 
6324   Level: intermediate
6325 
6326 .keywords: mesh, coordinates
6327 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6328 @*/
6329 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
6330 {
6331   DM             cdm;
6332   PetscErrorCode ierr;
6333 
6334   PetscFunctionBegin;
6335   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6336   PetscValidPointer(section, 2);
6337   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6338   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
6339   PetscFunctionReturn(0);
6340 }
6341 
6342 #undef __FUNCT__
6343 #define __FUNCT__ "DMPlexSetCoordinateSection"
6344 /*@
6345   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
6346 
6347   Not Collective
6348 
6349   Input Parameters:
6350 + dm      - The DMPlex object
6351 - section - The PetscSection object
6352 
6353   Level: intermediate
6354 
6355 .keywords: mesh, coordinates
6356 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6357 @*/
6358 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
6359 {
6360   DM             cdm;
6361   PetscErrorCode ierr;
6362 
6363   PetscFunctionBegin;
6364   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6365   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
6366   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6367   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
6368   PetscFunctionReturn(0);
6369 }
6370 
6371 #undef __FUNCT__
6372 #define __FUNCT__ "DMPlexGetConeSection"
6373 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
6374 {
6375   DM_Plex *mesh = (DM_Plex*) dm->data;
6376 
6377   PetscFunctionBegin;
6378   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6379   if (section) *section = mesh->coneSection;
6380   PetscFunctionReturn(0);
6381 }
6382 
6383 #undef __FUNCT__
6384 #define __FUNCT__ "DMPlexGetCones"
6385 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
6386 {
6387   DM_Plex *mesh = (DM_Plex*) dm->data;
6388 
6389   PetscFunctionBegin;
6390   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6391   if (cones) *cones = mesh->cones;
6392   PetscFunctionReturn(0);
6393 }
6394 
6395 #undef __FUNCT__
6396 #define __FUNCT__ "DMPlexGetConeOrientations"
6397 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
6398 {
6399   DM_Plex *mesh = (DM_Plex*) dm->data;
6400 
6401   PetscFunctionBegin;
6402   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6403   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
6404   PetscFunctionReturn(0);
6405 }
6406 
6407 /******************************** FEM Support **********************************/
6408 
6409 #undef __FUNCT__
6410 #define __FUNCT__ "DMPlexVecGetClosure"
6411 /*@C
6412   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6413 
6414   Not collective
6415 
6416   Input Parameters:
6417 + dm - The DM
6418 . section - The section describing the layout in v, or NULL to use the default section
6419 . v - The local vector
6420 - point - The sieve point in the DM
6421 
6422   Output Parameters:
6423 + csize - The number of values in the closure, or NULL
6424 - values - The array of values, which is a borrowed array and should not be freed
6425 
6426   Fortran Notes:
6427   Since it returns an array, this routine is only available in Fortran 90, and you must
6428   include petsc.h90 in your code.
6429 
6430   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6431 
6432   Level: intermediate
6433 
6434 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6435 @*/
6436 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6437 {
6438   PetscScalar   *array, *vArray;
6439   PetscInt      *points = NULL;
6440   PetscInt       offsets[32];
6441   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
6442   PetscErrorCode ierr;
6443 
6444   PetscFunctionBegin;
6445   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6446   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6447   if (!section) {
6448     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6449   }
6450   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6451   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6452   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6453   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6454   /* Compress out points not in the section */
6455   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6456   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6457     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6458       points[q*2]   = points[p];
6459       points[q*2+1] = points[p+1];
6460       ++q;
6461     }
6462   }
6463   numPoints = q;
6464   for (p = 0, size = 0; p < numPoints*2; p += 2) {
6465     PetscInt dof, fdof;
6466 
6467     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6468     for (f = 0; f < numFields; ++f) {
6469       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6470       offsets[f+1] += fdof;
6471     }
6472     size += dof;
6473   }
6474   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6475   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
6476   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
6477   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
6478   for (p = 0; p < numPoints*2; p += 2) {
6479     PetscInt     o = points[p+1];
6480     PetscInt     dof, off, d;
6481     PetscScalar *varr;
6482 
6483     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6484     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
6485     varr = &vArray[off];
6486     if (numFields) {
6487       PetscInt fdof, foff, fcomp, f, c;
6488 
6489       for (f = 0, foff = 0; f < numFields; ++f) {
6490         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6491         if (o >= 0) {
6492           for (d = 0; d < fdof; ++d, ++offsets[f]) {
6493             array[offsets[f]] = varr[foff+d];
6494           }
6495         } else {
6496           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6497           for (d = fdof/fcomp-1; d >= 0; --d) {
6498             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
6499               array[offsets[f]] = varr[foff+d*fcomp+c];
6500             }
6501           }
6502         }
6503         foff += fdof;
6504       }
6505     } else {
6506       if (o >= 0) {
6507         for (d = 0; d < dof; ++d, ++offsets[0]) {
6508           array[offsets[0]] = varr[d];
6509         }
6510       } else {
6511         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
6512           array[offsets[0]] = varr[d];
6513         }
6514       }
6515     }
6516   }
6517   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6518   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
6519   if (csize) *csize = size;
6520   *values = array;
6521   PetscFunctionReturn(0);
6522 }
6523 
6524 #undef __FUNCT__
6525 #define __FUNCT__ "DMPlexVecRestoreClosure"
6526 /*@C
6527   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6528 
6529   Not collective
6530 
6531   Input Parameters:
6532 + dm - The DM
6533 . section - The section describing the layout in v, or NULL to use the default section
6534 . v - The local vector
6535 . point - The sieve point in the DM
6536 . csize - The number of values in the closure, or NULL
6537 - values - The array of values, which is a borrowed array and should not be freed
6538 
6539   Fortran Notes:
6540   Since it returns an array, this routine is only available in Fortran 90, and you must
6541   include petsc.h90 in your code.
6542 
6543   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6544 
6545   Level: intermediate
6546 
6547 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6548 @*/
6549 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6550 {
6551   PetscInt       size = 0;
6552   PetscErrorCode ierr;
6553 
6554   PetscFunctionBegin;
6555   /* Should work without recalculating size */
6556   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
6557   PetscFunctionReturn(0);
6558 }
6559 
6560 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
6561 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
6562 
6563 #undef __FUNCT__
6564 #define __FUNCT__ "updatePoint_private"
6565 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6566 {
6567   PetscInt        cdof;   /* The number of constraints on this point */
6568   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6569   PetscScalar    *a;
6570   PetscInt        off, cind = 0, k;
6571   PetscErrorCode  ierr;
6572 
6573   PetscFunctionBegin;
6574   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6575   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6576   a    = &array[off];
6577   if (!cdof || setBC) {
6578     if (orientation >= 0) {
6579       for (k = 0; k < dof; ++k) {
6580         fuse(&a[k], values[k]);
6581       }
6582     } else {
6583       for (k = 0; k < dof; ++k) {
6584         fuse(&a[k], values[dof-k-1]);
6585       }
6586     }
6587   } else {
6588     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6589     if (orientation >= 0) {
6590       for (k = 0; k < dof; ++k) {
6591         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6592         fuse(&a[k], values[k]);
6593       }
6594     } else {
6595       for (k = 0; k < dof; ++k) {
6596         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6597         fuse(&a[k], values[dof-k-1]);
6598       }
6599     }
6600   }
6601   PetscFunctionReturn(0);
6602 }
6603 
6604 #undef __FUNCT__
6605 #define __FUNCT__ "updatePointFields_private"
6606 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6607 {
6608   PetscScalar   *a;
6609   PetscInt       numFields, off, foff, f;
6610   PetscErrorCode ierr;
6611 
6612   PetscFunctionBegin;
6613   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6614   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6615   a    = &array[off];
6616   for (f = 0, foff = 0; f < numFields; ++f) {
6617     PetscInt        fdof, fcomp, fcdof;
6618     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6619     PetscInt        cind = 0, k, c;
6620 
6621     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6622     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6623     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6624     if (!fcdof || setBC) {
6625       if (orientation >= 0) {
6626         for (k = 0; k < fdof; ++k) {
6627           fuse(&a[foff+k], values[foffs[f]+k]);
6628         }
6629       } else {
6630         for (k = fdof/fcomp-1; k >= 0; --k) {
6631           for (c = 0; c < fcomp; ++c) {
6632             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6633           }
6634         }
6635       }
6636     } else {
6637       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6638       if (orientation >= 0) {
6639         for (k = 0; k < fdof; ++k) {
6640           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
6641           fuse(&a[foff+k], values[foffs[f]+k]);
6642         }
6643       } else {
6644         for (k = fdof/fcomp-1; k >= 0; --k) {
6645           for (c = 0; c < fcomp; ++c) {
6646             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
6647             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6648           }
6649         }
6650       }
6651     }
6652     foff     += fdof;
6653     foffs[f] += fdof;
6654   }
6655   PetscFunctionReturn(0);
6656 }
6657 
6658 #undef __FUNCT__
6659 #define __FUNCT__ "DMPlexVecSetClosure"
6660 /*@C
6661   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6662 
6663   Not collective
6664 
6665   Input Parameters:
6666 + dm - The DM
6667 . section - The section describing the layout in v, or NULL to use the default section
6668 . v - The local vector
6669 . point - The sieve point in the DM
6670 . values - The array of values
6671 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6672 
6673   Fortran Notes:
6674   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6675 
6676   Level: intermediate
6677 
6678 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6679 @*/
6680 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6681 {
6682   PetscScalar   *array;
6683   PetscInt      *points = NULL;
6684   PetscInt       offsets[32];
6685   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
6686   PetscErrorCode ierr;
6687 
6688   PetscFunctionBegin;
6689   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6690   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6691   if (!section) {
6692     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6693   }
6694   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6695   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6696   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6697   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6698   /* Compress out points not in the section */
6699   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6700   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6701     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6702       points[q*2]   = points[p];
6703       points[q*2+1] = points[p+1];
6704       ++q;
6705     }
6706   }
6707   numPoints = q;
6708   for (p = 0; p < numPoints*2; p += 2) {
6709     PetscInt fdof;
6710 
6711     for (f = 0; f < numFields; ++f) {
6712       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6713       offsets[f+1] += fdof;
6714     }
6715   }
6716   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6717   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6718   if (numFields) {
6719     switch (mode) {
6720     case INSERT_VALUES:
6721       for (p = 0; p < numPoints*2; p += 2) {
6722         PetscInt o = points[p+1];
6723         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
6724       } break;
6725     case INSERT_ALL_VALUES:
6726       for (p = 0; p < numPoints*2; p += 2) {
6727         PetscInt o = points[p+1];
6728         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
6729       } break;
6730     case ADD_VALUES:
6731       for (p = 0; p < numPoints*2; p += 2) {
6732         PetscInt o = points[p+1];
6733         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
6734       } break;
6735     case ADD_ALL_VALUES:
6736       for (p = 0; p < numPoints*2; p += 2) {
6737         PetscInt o = points[p+1];
6738         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
6739       } break;
6740     default:
6741       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6742     }
6743   } else {
6744     switch (mode) {
6745     case INSERT_VALUES:
6746       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6747         PetscInt o = points[p+1];
6748         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6749         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
6750       } break;
6751     case INSERT_ALL_VALUES:
6752       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6753         PetscInt o = points[p+1];
6754         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6755         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
6756       } break;
6757     case ADD_VALUES:
6758       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6759         PetscInt o = points[p+1];
6760         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6761         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
6762       } break;
6763     case ADD_ALL_VALUES:
6764       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6765         PetscInt o = points[p+1];
6766         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6767         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
6768       } break;
6769     default:
6770       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6771     }
6772   }
6773   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6774   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6775   PetscFunctionReturn(0);
6776 }
6777 
6778 #undef __FUNCT__
6779 #define __FUNCT__ "DMPlexPrintMatSetValues"
6780 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
6781 {
6782   PetscMPIInt    rank;
6783   PetscInt       i, j;
6784   PetscErrorCode ierr;
6785 
6786   PetscFunctionBegin;
6787   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
6788   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
6789   for (i = 0; i < numIndices; i++) {
6790     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
6791   }
6792   for (i = 0; i < numIndices; i++) {
6793     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
6794     for (j = 0; j < numIndices; j++) {
6795 #if defined(PETSC_USE_COMPLEX)
6796       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
6797 #else
6798       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
6799 #endif
6800     }
6801     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
6802   }
6803   PetscFunctionReturn(0);
6804 }
6805 
6806 #undef __FUNCT__
6807 #define __FUNCT__ "indicesPoint_private"
6808 /* . off - The global offset of this point */
6809 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
6810 {
6811   PetscInt        dof;    /* The number of unknowns on this point */
6812   PetscInt        cdof;   /* The number of constraints on this point */
6813   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6814   PetscInt        cind = 0, k;
6815   PetscErrorCode  ierr;
6816 
6817   PetscFunctionBegin;
6818   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6819   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6820   if (!cdof || setBC) {
6821     if (orientation >= 0) {
6822       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
6823     } else {
6824       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
6825     }
6826   } else {
6827     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6828     if (orientation >= 0) {
6829       for (k = 0; k < dof; ++k) {
6830         if ((cind < cdof) && (k == cdofs[cind])) {
6831           /* Insert check for returning constrained indices */
6832           indices[*loff+k] = -(off+k+1);
6833           ++cind;
6834         } else {
6835           indices[*loff+k] = off+k-cind;
6836         }
6837       }
6838     } else {
6839       for (k = 0; k < dof; ++k) {
6840         if ((cind < cdof) && (k == cdofs[cind])) {
6841           /* Insert check for returning constrained indices */
6842           indices[*loff+dof-k-1] = -(off+k+1);
6843           ++cind;
6844         } else {
6845           indices[*loff+dof-k-1] = off+k-cind;
6846         }
6847       }
6848     }
6849   }
6850   *loff += dof;
6851   PetscFunctionReturn(0);
6852 }
6853 
6854 #undef __FUNCT__
6855 #define __FUNCT__ "indicesPointFields_private"
6856 /* . off - The global offset of this point */
6857 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
6858 {
6859   PetscInt       numFields, foff, f;
6860   PetscErrorCode ierr;
6861 
6862   PetscFunctionBegin;
6863   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6864   for (f = 0, foff = 0; f < numFields; ++f) {
6865     PetscInt        fdof, fcomp, cfdof;
6866     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6867     PetscInt        cind = 0, k, c;
6868 
6869     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6870     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6871     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6872     if (!cfdof || setBC) {
6873       if (orientation >= 0) {
6874         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
6875       } else {
6876         for (k = fdof/fcomp-1; k >= 0; --k) {
6877           for (c = 0; c < fcomp; ++c) {
6878             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
6879           }
6880         }
6881       }
6882     } else {
6883       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6884       if (orientation >= 0) {
6885         for (k = 0; k < fdof; ++k) {
6886           if ((cind < cfdof) && (k == fcdofs[cind])) {
6887             indices[foffs[f]+k] = -(off+foff+k+1);
6888             ++cind;
6889           } else {
6890             indices[foffs[f]+k] = off+foff+k-cind;
6891           }
6892         }
6893       } else {
6894         for (k = fdof/fcomp-1; k >= 0; --k) {
6895           for (c = 0; c < fcomp; ++c) {
6896             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
6897               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
6898               ++cind;
6899             } else {
6900               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
6901             }
6902           }
6903         }
6904       }
6905     }
6906     foff     += fdof - cfdof;
6907     foffs[f] += fdof;
6908   }
6909   PetscFunctionReturn(0);
6910 }
6911 
6912 #undef __FUNCT__
6913 #define __FUNCT__ "DMPlexMatSetClosure"
6914 /*@C
6915   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
6916 
6917   Not collective
6918 
6919   Input Parameters:
6920 + dm - The DM
6921 . section - The section describing the layout in v, or NULL to use the default section
6922 . globalSection - The section describing the layout in v, or NULL to use the default section
6923 . A - The matrix
6924 . point - The sieve point in the DM
6925 . values - The array of values
6926 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6927 
6928   Fortran Notes:
6929   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6930 
6931   Level: intermediate
6932 
6933 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
6934 @*/
6935 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6936 {
6937   DM_Plex       *mesh   = (DM_Plex*) dm->data;
6938   PetscInt      *points = NULL;
6939   PetscInt      *indices;
6940   PetscInt       offsets[32];
6941   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
6942   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
6943   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
6944   PetscErrorCode ierr;
6945 
6946   PetscFunctionBegin;
6947   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6948   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
6949   if (useDefault) {
6950     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6951   }
6952   if (useGlobalDefault) {
6953     if (useDefault) {
6954       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
6955     } else {
6956       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6957     }
6958   }
6959   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6960   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6961   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6962   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6963   /* Compress out points not in the section */
6964   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6965   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6966     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6967       points[q*2]   = points[p];
6968       points[q*2+1] = points[p+1];
6969       ++q;
6970     }
6971   }
6972   numPoints = q;
6973   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
6974     PetscInt fdof;
6975 
6976     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6977     for (f = 0; f < numFields; ++f) {
6978       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6979       offsets[f+1] += fdof;
6980     }
6981     numIndices += dof;
6982   }
6983   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6984 
6985   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
6986   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
6987   if (numFields) {
6988     for (p = 0; p < numPoints*2; p += 2) {
6989       PetscInt o = points[p+1];
6990       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
6991       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
6992     }
6993   } else {
6994     for (p = 0, off = 0; p < numPoints*2; p += 2) {
6995       PetscInt o = points[p+1];
6996       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
6997       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
6998     }
6999   }
7000   if (useGlobalDefault && !useDefault) {
7001     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7002   }
7003   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
7004   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7005   if (ierr) {
7006     PetscMPIInt    rank;
7007     PetscErrorCode ierr2;
7008 
7009     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
7010     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7011     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
7012     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
7013     CHKERRQ(ierr);
7014   }
7015   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7016   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7017   PetscFunctionReturn(0);
7018 }
7019 
7020 #undef __FUNCT__
7021 #define __FUNCT__ "DMPlexGetHybridBounds"
7022 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
7023 {
7024   DM_Plex       *mesh = (DM_Plex*) dm->data;
7025   PetscInt       dim;
7026   PetscErrorCode ierr;
7027 
7028   PetscFunctionBegin;
7029   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7030   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7031   if (cMax) *cMax = mesh->hybridPointMax[dim];
7032   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
7033   if (eMax) *eMax = mesh->hybridPointMax[1];
7034   if (vMax) *vMax = mesh->hybridPointMax[0];
7035   PetscFunctionReturn(0);
7036 }
7037 
7038 #undef __FUNCT__
7039 #define __FUNCT__ "DMPlexSetHybridBounds"
7040 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
7041 {
7042   DM_Plex       *mesh = (DM_Plex*) dm->data;
7043   PetscInt       dim;
7044   PetscErrorCode ierr;
7045 
7046   PetscFunctionBegin;
7047   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7048   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7049   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
7050   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
7051   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
7052   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
7053   PetscFunctionReturn(0);
7054 }
7055 
7056 #undef __FUNCT__
7057 #define __FUNCT__ "DMPlexGetVTKCellHeight"
7058 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7059 {
7060   DM_Plex *mesh = (DM_Plex*) dm->data;
7061 
7062   PetscFunctionBegin;
7063   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7064   PetscValidPointer(cellHeight, 2);
7065   *cellHeight = mesh->vtkCellHeight;
7066   PetscFunctionReturn(0);
7067 }
7068 
7069 #undef __FUNCT__
7070 #define __FUNCT__ "DMPlexSetVTKCellHeight"
7071 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7072 {
7073   DM_Plex *mesh = (DM_Plex*) dm->data;
7074 
7075   PetscFunctionBegin;
7076   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7077   mesh->vtkCellHeight = cellHeight;
7078   PetscFunctionReturn(0);
7079 }
7080 
7081 #undef __FUNCT__
7082 #define __FUNCT__ "DMPlexCreateNumbering_Private"
7083 /* We can easily have a form that takes an IS instead */
7084 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
7085 {
7086   PetscSection   section, globalSection;
7087   PetscInt      *numbers, p;
7088   PetscErrorCode ierr;
7089 
7090   PetscFunctionBegin;
7091   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7092   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
7093   for (p = pStart; p < pEnd; ++p) {
7094     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
7095   }
7096   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
7097   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7098   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
7099   for (p = pStart; p < pEnd; ++p) {
7100     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
7101   }
7102   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
7103   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7104   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7105   PetscFunctionReturn(0);
7106 }
7107 
7108 #undef __FUNCT__
7109 #define __FUNCT__ "DMPlexGetCellNumbering"
7110 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
7111 {
7112   DM_Plex       *mesh = (DM_Plex*) dm->data;
7113   PetscInt       cellHeight, cStart, cEnd, cMax;
7114   PetscErrorCode ierr;
7115 
7116   PetscFunctionBegin;
7117   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7118   if (!mesh->globalCellNumbers) {
7119     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
7120     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
7121     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7122     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7123     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
7124   }
7125   *globalCellNumbers = mesh->globalCellNumbers;
7126   PetscFunctionReturn(0);
7127 }
7128 
7129 #undef __FUNCT__
7130 #define __FUNCT__ "DMPlexGetVertexNumbering"
7131 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
7132 {
7133   DM_Plex       *mesh = (DM_Plex*) dm->data;
7134   PetscInt       vStart, vEnd, vMax;
7135   PetscErrorCode ierr;
7136 
7137   PetscFunctionBegin;
7138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7139   if (!mesh->globalVertexNumbers) {
7140     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7141     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
7142     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
7143     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
7144   }
7145   *globalVertexNumbers = mesh->globalVertexNumbers;
7146   PetscFunctionReturn(0);
7147 }
7148 
7149 
7150 #undef __FUNCT__
7151 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
7152 /*@C
7153   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
7154   the local section and an SF describing the section point overlap.
7155 
7156   Input Parameters:
7157   + s - The PetscSection for the local field layout
7158   . sf - The SF describing parallel layout of the section points
7159   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
7160   . label - The label specifying the points
7161   - labelValue - The label stratum specifying the points
7162 
7163   Output Parameter:
7164   . gsection - The PetscSection for the global field layout
7165 
7166   Note: This gives negative sizes and offsets to points not owned by this process
7167 
7168   Level: developer
7169 
7170 .seealso: PetscSectionCreate()
7171 @*/
7172 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
7173 {
7174   PetscInt      *neg;
7175   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
7176   PetscErrorCode ierr;
7177 
7178   PetscFunctionBegin;
7179   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
7180   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
7181   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
7182   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
7183   /* Mark ghost points with negative dof */
7184   for (p = pStart; p < pEnd; ++p) {
7185     PetscInt value;
7186 
7187     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
7188     if (value != labelValue) continue;
7189     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
7190     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
7191     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
7192     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
7193     neg[p-pStart] = -(dof+1);
7194   }
7195   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
7196   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
7197   if (nroots >= 0) {
7198     if (nroots > pEnd - pStart) {
7199       PetscInt *tmpDof;
7200       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7201       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
7202       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
7203       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
7204       for (p = pStart; p < pEnd; ++p) {
7205         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
7206       }
7207       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
7208     } else {
7209       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
7210       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
7211     }
7212   }
7213   /* Calculate new sizes, get proccess offset, and calculate point offsets */
7214   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7215     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
7216 
7217     (*gsection)->atlasOff[p] = off;
7218 
7219     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
7220   }
7221   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
7222   globalOff -= off;
7223   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7224     (*gsection)->atlasOff[p] += globalOff;
7225 
7226     neg[p] = -((*gsection)->atlasOff[p]+1);
7227   }
7228   /* Put in negative offsets for ghost points */
7229   if (nroots >= 0) {
7230     if (nroots > pEnd - pStart) {
7231       PetscInt *tmpOff;
7232       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7233       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
7234       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
7235       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
7236       for (p = pStart; p < pEnd; ++p) {
7237         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
7238       }
7239       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
7240     } else {
7241       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
7242       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
7243     }
7244   }
7245   ierr = PetscFree(neg);CHKERRQ(ierr);
7246   PetscFunctionReturn(0);
7247 }
7248