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