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