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