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