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