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