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