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