xref: /petsc/src/dm/impls/plex/plex.c (revision 6ac5842e34eedc6428162d8d42bedaaf46eae34c)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/vecimpl.h>
4 #include <petsc-private/isimpl.h>
5 
6 /* Logging support */
7 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
8 
9 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 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     PetscMPIInt size;
282 
283     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
284     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
285     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
286     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
287     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
288     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
289     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
290     if (depth == 1) {
291       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
292       pEnd = pEnd - pStart;
293       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
294       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
295       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
296       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
297       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
298       pEnd = pEnd - pStart;
299       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
300       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
301       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
302       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
303     } else {
304       for (d = 0; d <= dim; d++) {
305         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
306         pEnd = pEnd - pStart;
307         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
308         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
309         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
310         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
311       }
312     }
313     ierr = PetscFree(sizes);CHKERRQ(ierr);
314   }
315   PetscFunctionReturn(0);
316 }
317 
318 #undef __FUNCT__
319 #define __FUNCT__ "DMView_Plex"
320 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
321 {
322   PetscBool      iascii, isbinary;
323   PetscErrorCode ierr;
324 
325   PetscFunctionBegin;
326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
327   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
329   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
330   if (iascii) {
331     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
332 #if 0
333   } else if (isbinary) {
334     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
335 #endif
336   }
337   PetscFunctionReturn(0);
338 }
339 
340 #undef __FUNCT__
341 #define __FUNCT__ "DMDestroy_Plex"
342 PetscErrorCode DMDestroy_Plex(DM dm)
343 {
344   DM_Plex       *mesh = (DM_Plex*) dm->data;
345   DMLabel        next  = mesh->labels;
346   PetscErrorCode ierr;
347 
348   PetscFunctionBegin;
349   if (--mesh->refct > 0) PetscFunctionReturn(0);
350   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
353   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
355   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
356   while (next) {
357     DMLabel tmp = next->next;
358 
359     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
360     next = tmp;
361   }
362   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
364   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
365   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
366   ierr = PetscFree(mesh);CHKERRQ(ierr);
367   PetscFunctionReturn(0);
368 }
369 
370 #undef __FUNCT__
371 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
372 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
373 {
374   const PetscInt *support = NULL;
375   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
376   PetscErrorCode  ierr;
377 
378   PetscFunctionBegin;
379   if (useClosure) {
380     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
381     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
382     for (s = 0; s < supportSize; ++s) {
383       const PetscInt *cone = NULL;
384       PetscInt        coneSize, c, q;
385 
386       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
387       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
388       for (c = 0; c < coneSize; ++c) {
389         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
390           if (cone[c] == adj[q]) break;
391         }
392         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
393       }
394     }
395   } else {
396     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
397     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
398     for (s = 0; s < supportSize; ++s) {
399       const PetscInt *cone = NULL;
400       PetscInt        coneSize, c, q;
401 
402       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
403       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
404       for (c = 0; c < coneSize; ++c) {
405         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
406           if (cone[c] == adj[q]) break;
407         }
408         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
409       }
410     }
411   }
412   *adjSize = numAdj;
413   PetscFunctionReturn(0);
414 }
415 
416 #undef __FUNCT__
417 #define __FUNCT__ "DMPlexGetAdjacency_Private"
418 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
419 {
420   const PetscInt *star  = tmpClosure;
421   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
422   PetscErrorCode  ierr;
423 
424   PetscFunctionBegin;
425   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
426   for (s = 2; s < starSize*2; s += 2) {
427     const PetscInt *closure = NULL;
428     PetscInt        closureSize, c, q;
429 
430     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
431     for (c = 0; c < closureSize*2; c += 2) {
432       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
433         if (closure[c] == adj[q]) break;
434       }
435       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
436     }
437     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
438   }
439   *adjSize = numAdj;
440   PetscFunctionReturn(0);
441 }
442 
443 #undef __FUNCT__
444 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
445 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
446 {
447   DM_Plex *mesh = (DM_Plex*) dm->data;
448 
449   PetscFunctionBegin;
450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
451   mesh->preallocCenterDim = preallocCenterDim;
452   PetscFunctionReturn(0);
453 }
454 
455 #undef __FUNCT__
456 #define __FUNCT__ "DMPlexPreallocateOperator"
457 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
458 {
459   DM_Plex           *mesh = (DM_Plex*) dm->data;
460   MPI_Comm           comm;
461   PetscSF            sf, sfDof, sfAdj;
462   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
463   PetscInt           nleaves, l, p;
464   const PetscInt    *leaves;
465   const PetscSFNode *remotes;
466   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
467   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
468   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
469   PetscLayout        rLayout;
470   PetscInt           locRows, rStart, rEnd, r;
471   PetscMPIInt        size;
472   PetscBool          useClosure, debug = PETSC_FALSE;
473   PetscErrorCode     ierr;
474 
475   PetscFunctionBegin;
476   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
477   ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr);
478   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
479   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
480   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
481   /* Create dof SF based on point SF */
482   if (debug) {
483     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
487     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
488     ierr = PetscSFView(sf, NULL);CHKERRQ(ierr);
489   }
490   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
491   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
492   if (debug) {
493     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
494     ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr);
495   }
496   /* Create section for dof adjacency (dof ==> # adj dof) */
497   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
498   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
499   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
500   if (mesh->preallocCenterDim == dim) {
501     useClosure = PETSC_FALSE;
502   } else if (mesh->preallocCenterDim == 0) {
503     useClosure = PETSC_TRUE;
504   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
505 
506   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
507   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
510   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
511   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
512   /*   Fill in the ghost dofs on the interface */
513   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
514   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
515   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
516 
517   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
518   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
519 
520   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
521 
522   /*
523    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
524     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
525        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
526     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
527        Create sfAdj connecting rootSectionAdj and leafSectionAdj
528     3. Visit unowned points on interface, write adjacencies to adj
529        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
530     4. Visit owned points on interface, write adjacencies to rootAdj
531        Remove redundancy in rootAdj
532    ** The last two traversals use transitive closure
533     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
534        Allocate memory addressed by sectionAdj (cols)
535     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
536    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
537   */
538 
539   for (l = 0; l < nleaves; ++l) {
540     PetscInt dof, off, d, q;
541     PetscInt p = leaves[l], numAdj = maxAdjSize;
542 
543     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
544     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
545     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
546     for (q = 0; q < numAdj; ++q) {
547       const PetscInt padj = tmpAdj[q];
548       PetscInt ndof, ncdof;
549 
550       if ((padj < pStart) || (padj >= pEnd)) continue;
551       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
552       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
553       for (d = off; d < off+dof; ++d) {
554         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
555       }
556     }
557   }
558   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
559   if (debug) {
560     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
561     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
562   }
563   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
564   if (size > 1) {
565     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
566     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
567   }
568   if (debug) {
569     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
570     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
571   }
572   /* Add in local adjacency sizes for owned dofs on interface (roots) */
573   for (p = pStart; p < pEnd; ++p) {
574     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
575 
576     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
577     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
578     if (!dof) continue;
579     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
580     if (adof <= 0) continue;
581     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
582     for (q = 0; q < numAdj; ++q) {
583       const PetscInt padj = tmpAdj[q];
584       PetscInt ndof, ncdof;
585 
586       if ((padj < pStart) || (padj >= pEnd)) continue;
587       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
588       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
589       for (d = off; d < off+dof; ++d) {
590         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
591       }
592     }
593   }
594   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
595   if (debug) {
596     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
597     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
598   }
599   /* Create adj SF based on dof SF */
600   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
601   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
602   if (debug) {
603     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
604     ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr);
605   }
606   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
607   /* Create leaf adjacency */
608   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
609   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
610   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
611   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
612   for (l = 0; l < nleaves; ++l) {
613     PetscInt dof, off, d, q;
614     PetscInt p = leaves[l], numAdj = maxAdjSize;
615 
616     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
617     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
618     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
619     for (d = off; d < off+dof; ++d) {
620       PetscInt aoff, i = 0;
621 
622       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
623       for (q = 0; q < numAdj; ++q) {
624         const PetscInt padj = tmpAdj[q];
625         PetscInt ndof, ncdof, ngoff, nd;
626 
627         if ((padj < pStart) || (padj >= pEnd)) continue;
628         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
629         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
630         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
631         for (nd = 0; nd < ndof-ncdof; ++nd) {
632           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
633           ++i;
634         }
635       }
636     }
637   }
638   /* Debugging */
639   if (debug) {
640     IS tmp;
641     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
642     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
643     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
644   }
645   /* Gather adjacenct indices to root */
646   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
647   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
648   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
649   if (size > 1) {
650     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
651     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
652   }
653   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
654   ierr = PetscFree(adj);CHKERRQ(ierr);
655   /* Debugging */
656   if (debug) {
657     IS tmp;
658     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
659     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
660     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
661   }
662   /* Add in local adjacency indices for owned dofs on interface (roots) */
663   for (p = pStart; p < pEnd; ++p) {
664     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
665 
666     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
667     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
668     if (!dof) continue;
669     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
670     if (adof <= 0) continue;
671     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
672     for (d = off; d < off+dof; ++d) {
673       PetscInt adof, aoff, i;
674 
675       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
676       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
677       i    = adof-1;
678       for (q = 0; q < numAdj; ++q) {
679         const PetscInt padj = tmpAdj[q];
680         PetscInt ndof, ncdof, ngoff, nd;
681 
682         if ((padj < pStart) || (padj >= pEnd)) continue;
683         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
684         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
685         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
686         for (nd = 0; nd < ndof-ncdof; ++nd) {
687           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
688           --i;
689         }
690       }
691     }
692   }
693   /* Debugging */
694   if (debug) {
695     IS tmp;
696     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
697     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
698     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
699   }
700   /* Compress indices */
701   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
702   for (p = pStart; p < pEnd; ++p) {
703     PetscInt dof, cdof, off, d;
704     PetscInt adof, aoff;
705 
706     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
707     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
708     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
709     if (!dof) continue;
710     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
711     if (adof <= 0) continue;
712     for (d = off; d < off+dof-cdof; ++d) {
713       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
714       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
715       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
716       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
717     }
718   }
719   /* Debugging */
720   if (debug) {
721     IS tmp;
722     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
723     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
724     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
725     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
726     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
727   }
728   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
729   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
730   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
731   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
732   for (p = pStart; p < pEnd; ++p) {
733     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
734     PetscBool found  = PETSC_TRUE;
735 
736     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
737     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
738     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
739     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
740     for (d = 0; d < dof-cdof; ++d) {
741       PetscInt ldof, rdof;
742 
743       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
744       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
745       if (ldof > 0) {
746         /* We do not own this point */
747       } else if (rdof > 0) {
748         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
749       } else {
750         found = PETSC_FALSE;
751       }
752     }
753     if (found) continue;
754     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
755     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
756     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
757     for (q = 0; q < numAdj; ++q) {
758       const PetscInt padj = tmpAdj[q];
759       PetscInt ndof, ncdof, noff;
760 
761       if ((padj < pStart) || (padj >= pEnd)) continue;
762       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
763       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
764       ierr = PetscSectionGetOffset(section, padj, &noff);CHKERRQ(ierr);
765       for (d = goff; d < goff+dof-cdof; ++d) {
766         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
767       }
768     }
769   }
770   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
771   if (debug) {
772     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
773     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
774   }
775   /* Get adjacent indices */
776   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
777   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
778   for (p = pStart; p < pEnd; ++p) {
779     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
780     PetscBool found  = PETSC_TRUE;
781 
782     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
783     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
784     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
785     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
786     for (d = 0; d < dof-cdof; ++d) {
787       PetscInt ldof, rdof;
788 
789       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
790       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
791       if (ldof > 0) {
792         /* We do not own this point */
793       } else if (rdof > 0) {
794         PetscInt aoff, roff;
795 
796         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
797         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
798         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
799       } else {
800         found = PETSC_FALSE;
801       }
802     }
803     if (found) continue;
804     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
805     for (d = goff; d < goff+dof-cdof; ++d) {
806       PetscInt adof, aoff, i = 0;
807 
808       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
809       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
810       for (q = 0; q < numAdj; ++q) {
811         const PetscInt  padj = tmpAdj[q];
812         PetscInt        ndof, ncdof, ngoff, nd;
813         const PetscInt *ncind;
814 
815         /* Adjacent points may not be in the section chart */
816         if ((padj < pStart) || (padj >= pEnd)) continue;
817         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
818         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
819         ierr = PetscSectionGetConstraintIndices(section, padj, &ncind);CHKERRQ(ierr);
820         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
821         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
822           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
823         }
824       }
825       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
826     }
827   }
828   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
829   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
830   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
831   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
832   /* Debugging */
833   if (debug) {
834     IS tmp;
835     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
836     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
837     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
838   }
839   /* Create allocation vectors from adjacency graph */
840   ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr);
841   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr);
842   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
843   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
844   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
845   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
846   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
847   /* Only loop over blocks of rows */
848   if (rStart%bs || rEnd%bs) SETERRQ3(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
849   for (r = rStart/bs; r < rEnd/bs; ++r) {
850     const PetscInt row = r*bs;
851     PetscInt       numCols, cStart, c;
852 
853     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
854     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
855     for (c = cStart; c < cStart+numCols; ++c) {
856       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
857         ++dnz[r-rStart];
858         if (cols[c] >= row) ++dnzu[r-rStart];
859       } else {
860         ++onz[r-rStart];
861         if (cols[c] >= row) ++onzu[r-rStart];
862       }
863     }
864   }
865   if (bs > 1) {
866     for (r = 0; r < locRows/bs; ++r) {
867       dnz[r]  /= bs;
868       onz[r]  /= bs;
869       dnzu[r] /= bs;
870       onzu[r] /= bs;
871     }
872   }
873   /* Set matrix pattern */
874   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
875   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
876   /* Fill matrix with zeros */
877   if (fillMatrix) {
878     PetscScalar *values;
879     PetscInt     maxRowLen = 0;
880 
881     for (r = rStart; r < rEnd; ++r) {
882       PetscInt len;
883 
884       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
885       maxRowLen = PetscMax(maxRowLen, len);
886     }
887     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
888     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
889     for (r = rStart; r < rEnd; ++r) {
890       PetscInt numCols, cStart;
891 
892       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
893       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
894       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
895     }
896     ierr = PetscFree(values);CHKERRQ(ierr);
897     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
898     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
899   }
900   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
901   ierr = PetscFree(cols);CHKERRQ(ierr);
902   PetscFunctionReturn(0);
903 }
904 
905 #if 0
906 #undef __FUNCT__
907 #define __FUNCT__ "DMPlexPreallocateOperator_2"
908 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
909 {
910   PetscInt       *tmpClosure,*tmpAdj,*visits;
911   PetscInt        c,cStart,cEnd,pStart,pEnd;
912   PetscErrorCode  ierr;
913 
914   PetscFunctionBegin;
915   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
916   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
917   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
918 
919   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
920 
921   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
922   npoints = pEnd - pStart;
923 
924   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
925   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
926   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
927   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
928   for (c=cStart; c<cEnd; c++) {
929     PetscInt *support = tmpClosure;
930     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
931     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
932   }
933   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
934   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
935   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
936   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
937 
938   ierr = PetscSFGetRanks();CHKERRQ(ierr);
939 
940 
941   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
942   for (c=cStart; c<cEnd; c++) {
943     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
944     /*
945      Depth-first walk of transitive closure.
946      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
947      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
948      */
949   }
950 
951   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
952   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
953   PetscFunctionReturn(0);
954 }
955 #endif
956 
957 #undef __FUNCT__
958 #define __FUNCT__ "DMCreateMatrix_Plex"
959 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
960 {
961   PetscSection   section, sectionGlobal;
962   PetscInt       bs = -1;
963   PetscInt       localSize;
964   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
965   PetscErrorCode ierr;
966 
967   PetscFunctionBegin;
968 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
969   ierr = MatInitializePackage(NULL);CHKERRQ(ierr);
970 #endif
971   if (!mtype) mtype = MATAIJ;
972   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
973   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
974   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
975   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
976   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
977   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
978   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
979   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
980   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
981   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
982   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
983   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
984   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
985   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
986   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
987   /* Check for symmetric storage */
988   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
989   if (isSymmetric) {
990     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
991   }
992   if (!isShell) {
993     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
994     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
995 
996     if (bs < 0) {
997       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
998         PetscInt pStart, pEnd, p, dof, cdof;
999 
1000         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1001         for (p = pStart; p < pEnd; ++p) {
1002           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
1003           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
1004           if (dof-cdof) {
1005             if (bs < 0) {
1006               bs = dof-cdof;
1007             } else if (bs != dof-cdof) {
1008               /* Layout does not admit a pointwise block size */
1009               bs = 1;
1010               break;
1011             }
1012           }
1013         }
1014         /* Must have same blocksize on all procs (some might have no points) */
1015         bsLocal = bs;
1016         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1017         bsLocal = bs < 0 ? bsMax : bs;
1018         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1019         if (bsMin != bsMax) {
1020           bs = 1;
1021         } else {
1022           bs = bsMax;
1023         }
1024       } else {
1025         bs = 1;
1026       }
1027     }
1028     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1029     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1030     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1031     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1032     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1033     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1034     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1035   }
1036   PetscFunctionReturn(0);
1037 }
1038 
1039 #undef __FUNCT__
1040 #define __FUNCT__ "DMPlexGetDimension"
1041 /*@
1042   DMPlexGetDimension - Return the topological mesh dimension
1043 
1044   Not collective
1045 
1046   Input Parameter:
1047 . mesh - The DMPlex
1048 
1049   Output Parameter:
1050 . dim - The topological mesh dimension
1051 
1052   Level: beginner
1053 
1054 .seealso: DMPlexCreate()
1055 @*/
1056 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1057 {
1058   DM_Plex *mesh = (DM_Plex*) dm->data;
1059 
1060   PetscFunctionBegin;
1061   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1062   PetscValidPointer(dim, 2);
1063   *dim = mesh->dim;
1064   PetscFunctionReturn(0);
1065 }
1066 
1067 #undef __FUNCT__
1068 #define __FUNCT__ "DMPlexSetDimension"
1069 /*@
1070   DMPlexSetDimension - Set the topological mesh dimension
1071 
1072   Collective on mesh
1073 
1074   Input Parameters:
1075 + mesh - The DMPlex
1076 - dim - The topological mesh dimension
1077 
1078   Level: beginner
1079 
1080 .seealso: DMPlexCreate()
1081 @*/
1082 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1083 {
1084   DM_Plex *mesh = (DM_Plex*) dm->data;
1085 
1086   PetscFunctionBegin;
1087   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1088   PetscValidLogicalCollectiveInt(dm, dim, 2);
1089   mesh->dim               = dim;
1090   mesh->preallocCenterDim = dim;
1091   PetscFunctionReturn(0);
1092 }
1093 
1094 #undef __FUNCT__
1095 #define __FUNCT__ "DMPlexGetChart"
1096 /*@
1097   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1098 
1099   Not collective
1100 
1101   Input Parameter:
1102 . mesh - The DMPlex
1103 
1104   Output Parameters:
1105 + pStart - The first mesh point
1106 - pEnd   - The upper bound for mesh points
1107 
1108   Level: beginner
1109 
1110 .seealso: DMPlexCreate(), DMPlexSetChart()
1111 @*/
1112 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1113 {
1114   DM_Plex       *mesh = (DM_Plex*) dm->data;
1115   PetscErrorCode ierr;
1116 
1117   PetscFunctionBegin;
1118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1119   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1120   PetscFunctionReturn(0);
1121 }
1122 
1123 #undef __FUNCT__
1124 #define __FUNCT__ "DMPlexSetChart"
1125 /*@
1126   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1127 
1128   Not collective
1129 
1130   Input Parameters:
1131 + mesh - The DMPlex
1132 . pStart - The first mesh point
1133 - pEnd   - The upper bound for mesh points
1134 
1135   Output Parameters:
1136 
1137   Level: beginner
1138 
1139 .seealso: DMPlexCreate(), DMPlexGetChart()
1140 @*/
1141 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1142 {
1143   DM_Plex       *mesh = (DM_Plex*) dm->data;
1144   PetscErrorCode ierr;
1145 
1146   PetscFunctionBegin;
1147   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1148   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1149   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1150   PetscFunctionReturn(0);
1151 }
1152 
1153 #undef __FUNCT__
1154 #define __FUNCT__ "DMPlexGetConeSize"
1155 /*@
1156   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1157 
1158   Not collective
1159 
1160   Input Parameters:
1161 + mesh - The DMPlex
1162 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1163 
1164   Output Parameter:
1165 . size - The cone size for point p
1166 
1167   Level: beginner
1168 
1169 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1170 @*/
1171 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1172 {
1173   DM_Plex       *mesh = (DM_Plex*) dm->data;
1174   PetscErrorCode ierr;
1175 
1176   PetscFunctionBegin;
1177   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1178   PetscValidPointer(size, 3);
1179   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1180   PetscFunctionReturn(0);
1181 }
1182 
1183 #undef __FUNCT__
1184 #define __FUNCT__ "DMPlexSetConeSize"
1185 /*@
1186   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1187 
1188   Not collective
1189 
1190   Input Parameters:
1191 + mesh - The DMPlex
1192 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1193 - size - The cone size for point p
1194 
1195   Output Parameter:
1196 
1197   Note:
1198   This should be called after DMPlexSetChart().
1199 
1200   Level: beginner
1201 
1202 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1203 @*/
1204 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1205 {
1206   DM_Plex       *mesh = (DM_Plex*) dm->data;
1207   PetscErrorCode ierr;
1208 
1209   PetscFunctionBegin;
1210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1211   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1212 
1213   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1214   PetscFunctionReturn(0);
1215 }
1216 
1217 #undef __FUNCT__
1218 #define __FUNCT__ "DMPlexGetCone"
1219 /*@C
1220   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1221 
1222   Not collective
1223 
1224   Input Parameters:
1225 + mesh - The DMPlex
1226 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1227 
1228   Output Parameter:
1229 . cone - An array of points which are on the in-edges for point p
1230 
1231   Level: beginner
1232 
1233   Note:
1234   This routine is not available in Fortran.
1235 
1236 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1237 @*/
1238 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1239 {
1240   DM_Plex       *mesh = (DM_Plex*) dm->data;
1241   PetscInt       off;
1242   PetscErrorCode ierr;
1243 
1244   PetscFunctionBegin;
1245   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1246   PetscValidPointer(cone, 3);
1247   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1248   *cone = &mesh->cones[off];
1249   PetscFunctionReturn(0);
1250 }
1251 
1252 #undef __FUNCT__
1253 #define __FUNCT__ "DMPlexSetCone"
1254 /*@
1255   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1256 
1257   Not collective
1258 
1259   Input Parameters:
1260 + mesh - The DMPlex
1261 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1262 - cone - An array of points which are on the in-edges for point p
1263 
1264   Output Parameter:
1265 
1266   Note:
1267   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1268 
1269   Level: beginner
1270 
1271 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1272 @*/
1273 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1274 {
1275   DM_Plex       *mesh = (DM_Plex*) dm->data;
1276   PetscInt       pStart, pEnd;
1277   PetscInt       dof, off, c;
1278   PetscErrorCode ierr;
1279 
1280   PetscFunctionBegin;
1281   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1282   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1283   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1284   if (dof) PetscValidPointer(cone, 3);
1285   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1286   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);
1287   for (c = 0; c < dof; ++c) {
1288     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);
1289     mesh->cones[off+c] = cone[c];
1290   }
1291   PetscFunctionReturn(0);
1292 }
1293 
1294 #undef __FUNCT__
1295 #define __FUNCT__ "DMPlexGetConeOrientation"
1296 /*@C
1297   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1298 
1299   Not collective
1300 
1301   Input Parameters:
1302 + mesh - The DMPlex
1303 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1304 
1305   Output Parameter:
1306 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1307                     integer giving the prescription for cone traversal. If it is negative, the cone is
1308                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1309                     the index of the cone point on which to start.
1310 
1311   Level: beginner
1312 
1313   Note:
1314   This routine is not available in Fortran.
1315 
1316 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1317 @*/
1318 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1319 {
1320   DM_Plex       *mesh = (DM_Plex*) dm->data;
1321   PetscInt       off;
1322   PetscErrorCode ierr;
1323 
1324   PetscFunctionBegin;
1325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1326 #if defined(PETSC_USE_DEBUG)
1327   {
1328     PetscInt dof;
1329     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1330     if (dof) PetscValidPointer(coneOrientation, 3);
1331   }
1332 #endif
1333   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1334 
1335   *coneOrientation = &mesh->coneOrientations[off];
1336   PetscFunctionReturn(0);
1337 }
1338 
1339 #undef __FUNCT__
1340 #define __FUNCT__ "DMPlexSetConeOrientation"
1341 /*@
1342   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1343 
1344   Not collective
1345 
1346   Input Parameters:
1347 + mesh - The DMPlex
1348 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1349 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1350                     integer giving the prescription for cone traversal. If it is negative, the cone is
1351                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1352                     the index of the cone point on which to start.
1353 
1354   Output Parameter:
1355 
1356   Note:
1357   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1358 
1359   Level: beginner
1360 
1361 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1362 @*/
1363 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1364 {
1365   DM_Plex       *mesh = (DM_Plex*) dm->data;
1366   PetscInt       pStart, pEnd;
1367   PetscInt       dof, off, c;
1368   PetscErrorCode ierr;
1369 
1370   PetscFunctionBegin;
1371   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1372   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1373   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1374   if (dof) PetscValidPointer(coneOrientation, 3);
1375   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1376   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);
1377   for (c = 0; c < dof; ++c) {
1378     PetscInt cdof, o = coneOrientation[c];
1379 
1380     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1381     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);
1382     mesh->coneOrientations[off+c] = o;
1383   }
1384   PetscFunctionReturn(0);
1385 }
1386 
1387 #undef __FUNCT__
1388 #define __FUNCT__ "DMPlexInsertCone"
1389 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1390 {
1391   DM_Plex       *mesh = (DM_Plex*) dm->data;
1392   PetscInt       pStart, pEnd;
1393   PetscInt       dof, off;
1394   PetscErrorCode ierr;
1395 
1396   PetscFunctionBegin;
1397   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1398   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1399   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);
1400   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);
1401   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1402   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1403   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);
1404   mesh->cones[off+conePos] = conePoint;
1405   PetscFunctionReturn(0);
1406 }
1407 
1408 #undef __FUNCT__
1409 #define __FUNCT__ "DMPlexInsertConeOrientation"
1410 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1411 {
1412   DM_Plex       *mesh = (DM_Plex*) dm->data;
1413   PetscInt       pStart, pEnd;
1414   PetscInt       dof, off;
1415   PetscErrorCode ierr;
1416 
1417   PetscFunctionBegin;
1418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1419   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1420   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);
1421   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1422   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1423   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);
1424   mesh->coneOrientations[off+conePos] = coneOrientation;
1425   PetscFunctionReturn(0);
1426 }
1427 
1428 #undef __FUNCT__
1429 #define __FUNCT__ "DMPlexGetSupportSize"
1430 /*@
1431   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1432 
1433   Not collective
1434 
1435   Input Parameters:
1436 + mesh - The DMPlex
1437 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1438 
1439   Output Parameter:
1440 . size - The support size for point p
1441 
1442   Level: beginner
1443 
1444 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1445 @*/
1446 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1447 {
1448   DM_Plex       *mesh = (DM_Plex*) dm->data;
1449   PetscErrorCode ierr;
1450 
1451   PetscFunctionBegin;
1452   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1453   PetscValidPointer(size, 3);
1454   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1455   PetscFunctionReturn(0);
1456 }
1457 
1458 #undef __FUNCT__
1459 #define __FUNCT__ "DMPlexSetSupportSize"
1460 /*@
1461   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1462 
1463   Not collective
1464 
1465   Input Parameters:
1466 + mesh - The DMPlex
1467 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1468 - size - The support size for point p
1469 
1470   Output Parameter:
1471 
1472   Note:
1473   This should be called after DMPlexSetChart().
1474 
1475   Level: beginner
1476 
1477 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1478 @*/
1479 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1480 {
1481   DM_Plex       *mesh = (DM_Plex*) dm->data;
1482   PetscErrorCode ierr;
1483 
1484   PetscFunctionBegin;
1485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1486   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1487 
1488   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1489   PetscFunctionReturn(0);
1490 }
1491 
1492 #undef __FUNCT__
1493 #define __FUNCT__ "DMPlexGetSupport"
1494 /*@C
1495   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1496 
1497   Not collective
1498 
1499   Input Parameters:
1500 + mesh - The DMPlex
1501 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1502 
1503   Output Parameter:
1504 . support - An array of points which are on the out-edges for point p
1505 
1506   Level: beginner
1507 
1508 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1509 @*/
1510 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1511 {
1512   DM_Plex       *mesh = (DM_Plex*) dm->data;
1513   PetscInt       off;
1514   PetscErrorCode ierr;
1515 
1516   PetscFunctionBegin;
1517   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1518   PetscValidPointer(support, 3);
1519   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1520   *support = &mesh->supports[off];
1521   PetscFunctionReturn(0);
1522 }
1523 
1524 #undef __FUNCT__
1525 #define __FUNCT__ "DMPlexSetSupport"
1526 /*@
1527   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1528 
1529   Not collective
1530 
1531   Input Parameters:
1532 + mesh - The DMPlex
1533 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1534 - support - An array of points which are on the in-edges for point p
1535 
1536   Output Parameter:
1537 
1538   Note:
1539   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1540 
1541   Level: beginner
1542 
1543 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1544 @*/
1545 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1546 {
1547   DM_Plex       *mesh = (DM_Plex*) dm->data;
1548   PetscInt       pStart, pEnd;
1549   PetscInt       dof, off, c;
1550   PetscErrorCode ierr;
1551 
1552   PetscFunctionBegin;
1553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1554   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1555   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1556   if (dof) PetscValidPointer(support, 3);
1557   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1558   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);
1559   for (c = 0; c < dof; ++c) {
1560     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);
1561     mesh->supports[off+c] = support[c];
1562   }
1563   PetscFunctionReturn(0);
1564 }
1565 
1566 #undef __FUNCT__
1567 #define __FUNCT__ "DMPlexInsertSupport"
1568 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1569 {
1570   DM_Plex       *mesh = (DM_Plex*) dm->data;
1571   PetscInt       pStart, pEnd;
1572   PetscInt       dof, off;
1573   PetscErrorCode ierr;
1574 
1575   PetscFunctionBegin;
1576   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1577   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1578   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1579   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1580   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);
1581   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);
1582   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);
1583   mesh->supports[off+supportPos] = supportPoint;
1584   PetscFunctionReturn(0);
1585 }
1586 
1587 #undef __FUNCT__
1588 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1589 /*@C
1590   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1591 
1592   Not collective
1593 
1594   Input Parameters:
1595 + mesh - The DMPlex
1596 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1597 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1598 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1599 
1600   Output Parameters:
1601 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1602 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1603 
1604   Note:
1605   If using internal storage (points is NULL on input), each call overwrites the last output.
1606 
1607   Level: beginner
1608 
1609 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1610 @*/
1611 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1612 {
1613   DM_Plex        *mesh = (DM_Plex*) dm->data;
1614   PetscInt       *closure, *fifo;
1615   const PetscInt *tmp = NULL, *tmpO = NULL;
1616   PetscInt        tmpSize, t;
1617   PetscInt        depth       = 0, maxSize;
1618   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1619   PetscErrorCode  ierr;
1620 
1621   PetscFunctionBegin;
1622   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1623   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1624   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1625   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1626   if (*points) {
1627     closure = *points;
1628   } else {
1629     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1630   }
1631   closure[0] = p; closure[1] = 0;
1632   /* This is only 1-level */
1633   if (useCone) {
1634     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1635     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1636     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1637   } else {
1638     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1639     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1640   }
1641   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1642     const PetscInt cp = tmp[t];
1643     const PetscInt co = tmpO ? tmpO[t] : 0;
1644 
1645     closure[closureSize]   = cp;
1646     closure[closureSize+1] = co;
1647     fifo[fifoSize]         = cp;
1648     fifo[fifoSize+1]       = co;
1649   }
1650   while (fifoSize - fifoStart) {
1651     const PetscInt q   = fifo[fifoStart];
1652     const PetscInt o   = fifo[fifoStart+1];
1653     const PetscInt rev = o >= 0 ? 0 : 1;
1654     const PetscInt off = rev ? -(o+1) : o;
1655 
1656     if (useCone) {
1657       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1658       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1659       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1660     } else {
1661       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1662       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1663       tmpO = NULL;
1664     }
1665     for (t = 0; t < tmpSize; ++t) {
1666       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1667       const PetscInt cp = tmp[i];
1668       /* Must propogate orientation */
1669       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1670       PetscInt       c;
1671 
1672       /* Check for duplicate */
1673       for (c = 0; c < closureSize; c += 2) {
1674         if (closure[c] == cp) break;
1675       }
1676       if (c == closureSize) {
1677         closure[closureSize]   = cp;
1678         closure[closureSize+1] = co;
1679         fifo[fifoSize]         = cp;
1680         fifo[fifoSize+1]       = co;
1681         closureSize           += 2;
1682         fifoSize              += 2;
1683       }
1684     }
1685     fifoStart += 2;
1686   }
1687   if (numPoints) *numPoints = closureSize/2;
1688   if (points)    *points    = closure;
1689   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1690   PetscFunctionReturn(0);
1691 }
1692 
1693 #undef __FUNCT__
1694 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1695 /*@C
1696   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1697 
1698   Not collective
1699 
1700   Input Parameters:
1701 + mesh - The DMPlex
1702 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1703 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1704 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1705 
1706   Output Parameters:
1707 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1708 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1709 
1710   Note:
1711   If not using internal storage (points is not NULL on input), this call is unnecessary
1712 
1713   Level: beginner
1714 
1715 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1716 @*/
1717 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1718 {
1719   PetscErrorCode ierr;
1720 
1721   PetscFunctionBegin;
1722   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1723   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1724   PetscFunctionReturn(0);
1725 }
1726 
1727 #undef __FUNCT__
1728 #define __FUNCT__ "DMPlexGetMaxSizes"
1729 /*@
1730   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1731 
1732   Not collective
1733 
1734   Input Parameter:
1735 . mesh - The DMPlex
1736 
1737   Output Parameters:
1738 + maxConeSize - The maximum number of in-edges
1739 - maxSupportSize - The maximum number of out-edges
1740 
1741   Level: beginner
1742 
1743 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1744 @*/
1745 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1746 {
1747   DM_Plex *mesh = (DM_Plex*) dm->data;
1748 
1749   PetscFunctionBegin;
1750   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1751   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1752   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1753   PetscFunctionReturn(0);
1754 }
1755 
1756 #undef __FUNCT__
1757 #define __FUNCT__ "DMSetUp_Plex"
1758 PetscErrorCode DMSetUp_Plex(DM dm)
1759 {
1760   DM_Plex       *mesh = (DM_Plex*) dm->data;
1761   PetscInt       size;
1762   PetscErrorCode ierr;
1763 
1764   PetscFunctionBegin;
1765   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1766   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1767   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1768   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1769   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1770   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1771   if (mesh->maxSupportSize) {
1772     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1773     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1774     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1775   }
1776   PetscFunctionReturn(0);
1777 }
1778 
1779 #undef __FUNCT__
1780 #define __FUNCT__ "DMCreateSubDM_Plex"
1781 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1782 {
1783   PetscSection   section, sectionGlobal;
1784   PetscInt      *subIndices;
1785   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1786   PetscErrorCode ierr;
1787 
1788   PetscFunctionBegin;
1789   if (!numFields) PetscFunctionReturn(0);
1790   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1791   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1792   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1793   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1794   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1795   if (numFields > nF) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1796   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1797   for (p = pStart; p < pEnd; ++p) {
1798     PetscInt gdof;
1799 
1800     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1801     if (gdof > 0) {
1802       for (f = 0; f < numFields; ++f) {
1803         PetscInt fdof, fcdof;
1804 
1805         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1806         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1807         subSize += fdof-fcdof;
1808       }
1809     }
1810   }
1811   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1812   for (p = pStart; p < pEnd; ++p) {
1813     PetscInt gdof, goff;
1814 
1815     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1816     if (gdof > 0) {
1817       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1818       for (f = 0; f < numFields; ++f) {
1819         PetscInt fdof, fcdof, fc, f2, poff = 0;
1820 
1821         /* Can get rid of this loop by storing field information in the global section */
1822         for (f2 = 0; f2 < fields[f]; ++f2) {
1823           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1824           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1825           poff += fdof-fcdof;
1826         }
1827         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1828         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1829         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1830           subIndices[subOff] = goff+poff+fc;
1831         }
1832       }
1833     }
1834   }
1835   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1836   if (subdm) {
1837     PetscSection subsection;
1838     PetscBool    haveNull = PETSC_FALSE;
1839     PetscInt     f, nf = 0;
1840 
1841     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1842     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1843     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1844     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1845     for (f = 0; f < numFields; ++f) {
1846       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1847       if ((*subdm)->nullspaceConstructors[f]) {
1848         haveNull = PETSC_TRUE;
1849         nf       = f;
1850       }
1851     }
1852     if (haveNull) {
1853       MatNullSpace nullSpace;
1854 
1855       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1856       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1857       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1858     }
1859     if (dm->fields) {
1860       if (nF != dm->numFields) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1861       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1862       for (f = 0; f < numFields; ++f) {
1863         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1864       }
1865       if (numFields == 1) {
1866         MatNullSpace space;
1867         Mat          pmat;
1868 
1869         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1870         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1871         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1872         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1873         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1874         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1875       }
1876     }
1877   }
1878   PetscFunctionReturn(0);
1879 }
1880 
1881 #undef __FUNCT__
1882 #define __FUNCT__ "DMPlexSymmetrize"
1883 /*@
1884   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1885 
1886   Not collective
1887 
1888   Input Parameter:
1889 . mesh - The DMPlex
1890 
1891   Output Parameter:
1892 
1893   Note:
1894   This should be called after all calls to DMPlexSetCone()
1895 
1896   Level: beginner
1897 
1898 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1899 @*/
1900 PetscErrorCode DMPlexSymmetrize(DM dm)
1901 {
1902   DM_Plex       *mesh = (DM_Plex*) dm->data;
1903   PetscInt      *offsets;
1904   PetscInt       supportSize;
1905   PetscInt       pStart, pEnd, p;
1906   PetscErrorCode ierr;
1907 
1908   PetscFunctionBegin;
1909   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1910   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1911   /* Calculate support sizes */
1912   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1913   for (p = pStart; p < pEnd; ++p) {
1914     PetscInt dof, off, c;
1915 
1916     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1917     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1918     for (c = off; c < off+dof; ++c) {
1919       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1920     }
1921   }
1922   for (p = pStart; p < pEnd; ++p) {
1923     PetscInt dof;
1924 
1925     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1926 
1927     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1928   }
1929   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1930   /* Calculate supports */
1931   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1932   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1933   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1934   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1935   for (p = pStart; p < pEnd; ++p) {
1936     PetscInt dof, off, c;
1937 
1938     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1939     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1940     for (c = off; c < off+dof; ++c) {
1941       const PetscInt q = mesh->cones[c];
1942       PetscInt       offS;
1943 
1944       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1945 
1946       mesh->supports[offS+offsets[q]] = p;
1947       ++offsets[q];
1948     }
1949   }
1950   ierr = PetscFree(offsets);CHKERRQ(ierr);
1951   PetscFunctionReturn(0);
1952 }
1953 
1954 #undef __FUNCT__
1955 #define __FUNCT__ "DMPlexSetDepth_Private"
1956 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1957 {
1958   PetscInt       d;
1959   PetscErrorCode ierr;
1960 
1961   PetscFunctionBegin;
1962   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1963   if (d < 0) {
1964     /* We are guaranteed that the point has a cone since the depth was not yet set */
1965     const PetscInt *cone = NULL;
1966     PetscInt        dCone;
1967 
1968     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1969     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1970     d    = dCone+1;
1971     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1972   }
1973   *depth = d;
1974   PetscFunctionReturn(0);
1975 }
1976 
1977 #undef __FUNCT__
1978 #define __FUNCT__ "DMPlexStratify"
1979 /*@
1980   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1981   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1982   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1983   the DAG.
1984 
1985   Not collective
1986 
1987   Input Parameter:
1988 . mesh - The DMPlex
1989 
1990   Output Parameter:
1991 
1992   Notes:
1993   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1994   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1995 
1996   This should be called after all calls to DMPlexSymmetrize()
1997 
1998   Level: beginner
1999 
2000 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2001 @*/
2002 PetscErrorCode DMPlexStratify(DM dm)
2003 {
2004   DM_Plex       *mesh = (DM_Plex*) dm->data;
2005   PetscInt       pStart, pEnd, p;
2006   PetscInt       numRoots = 0, numLeaves = 0;
2007   PetscErrorCode ierr;
2008 
2009   PetscFunctionBegin;
2010   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2011   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2012   /* Calculate depth */
2013   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2014   /* Initialize roots and count leaves */
2015   for (p = pStart; p < pEnd; ++p) {
2016     PetscInt coneSize, supportSize;
2017 
2018     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2019     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2020     if (!coneSize && supportSize) {
2021       ++numRoots;
2022       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2023     } else if (!supportSize && coneSize) {
2024       ++numLeaves;
2025     } else if (!supportSize && !coneSize) {
2026       /* Isolated points */
2027       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2028     }
2029   }
2030   if (numRoots + numLeaves == (pEnd - pStart)) {
2031     for (p = pStart; p < pEnd; ++p) {
2032       PetscInt coneSize, supportSize;
2033 
2034       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2035       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2036       if (!supportSize && coneSize) {
2037         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2038       }
2039     }
2040   } else {
2041     /* This might be slow since lookup is not fast */
2042     for (p = pStart; p < pEnd; ++p) {
2043       PetscInt depth;
2044 
2045       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2046     }
2047   }
2048   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2049   PetscFunctionReturn(0);
2050 }
2051 
2052 #undef __FUNCT__
2053 #define __FUNCT__ "DMPlexGetJoin"
2054 /*@C
2055   DMPlexGetJoin - Get an array for the join of the set of points
2056 
2057   Not Collective
2058 
2059   Input Parameters:
2060 + dm - The DMPlex object
2061 . numPoints - The number of input points for the join
2062 - points - The input points
2063 
2064   Output Parameters:
2065 + numCoveredPoints - The number of points in the join
2066 - coveredPoints - The points in the join
2067 
2068   Level: intermediate
2069 
2070   Note: Currently, this is restricted to a single level join
2071 
2072 .keywords: mesh
2073 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2074 @*/
2075 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2076 {
2077   DM_Plex       *mesh = (DM_Plex*) dm->data;
2078   PetscInt      *join[2];
2079   PetscInt       joinSize, i = 0;
2080   PetscInt       dof, off, p, c, m;
2081   PetscErrorCode ierr;
2082 
2083   PetscFunctionBegin;
2084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2085   PetscValidPointer(points, 2);
2086   PetscValidPointer(numCoveredPoints, 3);
2087   PetscValidPointer(coveredPoints, 4);
2088   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2089   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2090   /* Copy in support of first point */
2091   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2092   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2093   for (joinSize = 0; joinSize < dof; ++joinSize) {
2094     join[i][joinSize] = mesh->supports[off+joinSize];
2095   }
2096   /* Check each successive support */
2097   for (p = 1; p < numPoints; ++p) {
2098     PetscInt newJoinSize = 0;
2099 
2100     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2101     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2102     for (c = 0; c < dof; ++c) {
2103       const PetscInt point = mesh->supports[off+c];
2104 
2105       for (m = 0; m < joinSize; ++m) {
2106         if (point == join[i][m]) {
2107           join[1-i][newJoinSize++] = point;
2108           break;
2109         }
2110       }
2111     }
2112     joinSize = newJoinSize;
2113     i        = 1-i;
2114   }
2115   *numCoveredPoints = joinSize;
2116   *coveredPoints    = join[i];
2117   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2118   PetscFunctionReturn(0);
2119 }
2120 
2121 #undef __FUNCT__
2122 #define __FUNCT__ "DMPlexRestoreJoin"
2123 /*@C
2124   DMPlexRestoreJoin - Restore an array for the join of the set of points
2125 
2126   Not Collective
2127 
2128   Input Parameters:
2129 + dm - The DMPlex object
2130 . numPoints - The number of input points for the join
2131 - points - The input points
2132 
2133   Output Parameters:
2134 + numCoveredPoints - The number of points in the join
2135 - coveredPoints - The points in the join
2136 
2137   Level: intermediate
2138 
2139 .keywords: mesh
2140 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2141 @*/
2142 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2143 {
2144   PetscErrorCode ierr;
2145 
2146   PetscFunctionBegin;
2147   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2148   PetscValidPointer(coveredPoints, 4);
2149   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2150   PetscFunctionReturn(0);
2151 }
2152 
2153 #undef __FUNCT__
2154 #define __FUNCT__ "DMPlexGetFullJoin"
2155 /*@C
2156   DMPlexGetFullJoin - Get an array for the join of the set of points
2157 
2158   Not Collective
2159 
2160   Input Parameters:
2161 + dm - The DMPlex object
2162 . numPoints - The number of input points for the join
2163 - points - The input points
2164 
2165   Output Parameters:
2166 + numCoveredPoints - The number of points in the join
2167 - coveredPoints - The points in the join
2168 
2169   Level: intermediate
2170 
2171 .keywords: mesh
2172 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2173 @*/
2174 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2175 {
2176   DM_Plex       *mesh = (DM_Plex*) dm->data;
2177   PetscInt      *offsets, **closures;
2178   PetscInt      *join[2];
2179   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2180   PetscInt       p, d, c, m;
2181   PetscErrorCode ierr;
2182 
2183   PetscFunctionBegin;
2184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2185   PetscValidPointer(points, 2);
2186   PetscValidPointer(numCoveredPoints, 3);
2187   PetscValidPointer(coveredPoints, 4);
2188 
2189   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2190   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2191   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2192   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2193   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2194   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2195   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2196 
2197   for (p = 0; p < numPoints; ++p) {
2198     PetscInt closureSize;
2199 
2200     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2201 
2202     offsets[p*(depth+2)+0] = 0;
2203     for (d = 0; d < depth+1; ++d) {
2204       PetscInt pStart, pEnd, i;
2205 
2206       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2207       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2208         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2209           offsets[p*(depth+2)+d+1] = i;
2210           break;
2211         }
2212       }
2213       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2214     }
2215     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);
2216   }
2217   for (d = 0; d < depth+1; ++d) {
2218     PetscInt dof;
2219 
2220     /* Copy in support of first point */
2221     dof = offsets[d+1] - offsets[d];
2222     for (joinSize = 0; joinSize < dof; ++joinSize) {
2223       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2224     }
2225     /* Check each successive cone */
2226     for (p = 1; p < numPoints && joinSize; ++p) {
2227       PetscInt newJoinSize = 0;
2228 
2229       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2230       for (c = 0; c < dof; ++c) {
2231         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2232 
2233         for (m = 0; m < joinSize; ++m) {
2234           if (point == join[i][m]) {
2235             join[1-i][newJoinSize++] = point;
2236             break;
2237           }
2238         }
2239       }
2240       joinSize = newJoinSize;
2241       i        = 1-i;
2242     }
2243     if (joinSize) break;
2244   }
2245   *numCoveredPoints = joinSize;
2246   *coveredPoints    = join[i];
2247   for (p = 0; p < numPoints; ++p) {
2248     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2249   }
2250   ierr = PetscFree(closures);CHKERRQ(ierr);
2251   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2252   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2253   PetscFunctionReturn(0);
2254 }
2255 
2256 #undef __FUNCT__
2257 #define __FUNCT__ "DMPlexGetMeet"
2258 /*@C
2259   DMPlexGetMeet - Get an array for the meet of the set of points
2260 
2261   Not Collective
2262 
2263   Input Parameters:
2264 + dm - The DMPlex object
2265 . numPoints - The number of input points for the meet
2266 - points - The input points
2267 
2268   Output Parameters:
2269 + numCoveredPoints - The number of points in the meet
2270 - coveredPoints - The points in the meet
2271 
2272   Level: intermediate
2273 
2274   Note: Currently, this is restricted to a single level meet
2275 
2276 .keywords: mesh
2277 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2278 @*/
2279 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2280 {
2281   DM_Plex       *mesh = (DM_Plex*) dm->data;
2282   PetscInt      *meet[2];
2283   PetscInt       meetSize, i = 0;
2284   PetscInt       dof, off, p, c, m;
2285   PetscErrorCode ierr;
2286 
2287   PetscFunctionBegin;
2288   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2289   PetscValidPointer(points, 2);
2290   PetscValidPointer(numCoveringPoints, 3);
2291   PetscValidPointer(coveringPoints, 4);
2292   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2293   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2294   /* Copy in cone of first point */
2295   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2296   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2297   for (meetSize = 0; meetSize < dof; ++meetSize) {
2298     meet[i][meetSize] = mesh->cones[off+meetSize];
2299   }
2300   /* Check each successive cone */
2301   for (p = 1; p < numPoints; ++p) {
2302     PetscInt newMeetSize = 0;
2303 
2304     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2305     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2306     for (c = 0; c < dof; ++c) {
2307       const PetscInt point = mesh->cones[off+c];
2308 
2309       for (m = 0; m < meetSize; ++m) {
2310         if (point == meet[i][m]) {
2311           meet[1-i][newMeetSize++] = point;
2312           break;
2313         }
2314       }
2315     }
2316     meetSize = newMeetSize;
2317     i        = 1-i;
2318   }
2319   *numCoveringPoints = meetSize;
2320   *coveringPoints    = meet[i];
2321   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2322   PetscFunctionReturn(0);
2323 }
2324 
2325 #undef __FUNCT__
2326 #define __FUNCT__ "DMPlexRestoreMeet"
2327 /*@C
2328   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2329 
2330   Not Collective
2331 
2332   Input Parameters:
2333 + dm - The DMPlex object
2334 . numPoints - The number of input points for the meet
2335 - points - The input points
2336 
2337   Output Parameters:
2338 + numCoveredPoints - The number of points in the meet
2339 - coveredPoints - The points in the meet
2340 
2341   Level: intermediate
2342 
2343 .keywords: mesh
2344 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2345 @*/
2346 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2347 {
2348   PetscErrorCode ierr;
2349 
2350   PetscFunctionBegin;
2351   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2352   PetscValidPointer(coveredPoints, 4);
2353   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2354   PetscFunctionReturn(0);
2355 }
2356 
2357 #undef __FUNCT__
2358 #define __FUNCT__ "DMPlexGetFullMeet"
2359 /*@C
2360   DMPlexGetFullMeet - Get an array for the meet of the set of points
2361 
2362   Not Collective
2363 
2364   Input Parameters:
2365 + dm - The DMPlex object
2366 . numPoints - The number of input points for the meet
2367 - points - The input points
2368 
2369   Output Parameters:
2370 + numCoveredPoints - The number of points in the meet
2371 - coveredPoints - The points in the meet
2372 
2373   Level: intermediate
2374 
2375 .keywords: mesh
2376 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2377 @*/
2378 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2379 {
2380   DM_Plex       *mesh = (DM_Plex*) dm->data;
2381   PetscInt      *offsets, **closures;
2382   PetscInt      *meet[2];
2383   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2384   PetscInt       p, h, c, m;
2385   PetscErrorCode ierr;
2386 
2387   PetscFunctionBegin;
2388   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2389   PetscValidPointer(points, 2);
2390   PetscValidPointer(numCoveredPoints, 3);
2391   PetscValidPointer(coveredPoints, 4);
2392 
2393   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2394   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2395   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2396   maxSize = PetscPowInt(mesh->maxConeSize,height);
2397   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2398   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2399 
2400   for (p = 0; p < numPoints; ++p) {
2401     PetscInt closureSize;
2402 
2403     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2404 
2405     offsets[p*(height+2)+0] = 0;
2406     for (h = 0; h < height+1; ++h) {
2407       PetscInt pStart, pEnd, i;
2408 
2409       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2410       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2411         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2412           offsets[p*(height+2)+h+1] = i;
2413           break;
2414         }
2415       }
2416       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2417     }
2418     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);
2419   }
2420   for (h = 0; h < height+1; ++h) {
2421     PetscInt dof;
2422 
2423     /* Copy in cone of first point */
2424     dof = offsets[h+1] - offsets[h];
2425     for (meetSize = 0; meetSize < dof; ++meetSize) {
2426       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2427     }
2428     /* Check each successive cone */
2429     for (p = 1; p < numPoints && meetSize; ++p) {
2430       PetscInt newMeetSize = 0;
2431 
2432       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2433       for (c = 0; c < dof; ++c) {
2434         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2435 
2436         for (m = 0; m < meetSize; ++m) {
2437           if (point == meet[i][m]) {
2438             meet[1-i][newMeetSize++] = point;
2439             break;
2440           }
2441         }
2442       }
2443       meetSize = newMeetSize;
2444       i        = 1-i;
2445     }
2446     if (meetSize) break;
2447   }
2448   *numCoveredPoints = meetSize;
2449   *coveredPoints    = meet[i];
2450   for (p = 0; p < numPoints; ++p) {
2451     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2452   }
2453   ierr = PetscFree(closures);CHKERRQ(ierr);
2454   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2455   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2456   PetscFunctionReturn(0);
2457 }
2458 
2459 #undef __FUNCT__
2460 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2461 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2462 {
2463   MPI_Comm       comm;
2464   PetscErrorCode ierr;
2465 
2466   PetscFunctionBegin;
2467   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2468   PetscValidPointer(numFaceVertices,3);
2469   switch (cellDim) {
2470   case 0:
2471     *numFaceVertices = 0;
2472     break;
2473   case 1:
2474     *numFaceVertices = 1;
2475     break;
2476   case 2:
2477     switch (numCorners) {
2478     case 3: /* triangle */
2479       *numFaceVertices = 2; /* Edge has 2 vertices */
2480       break;
2481     case 4: /* quadrilateral */
2482       *numFaceVertices = 2; /* Edge has 2 vertices */
2483       break;
2484     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2485       *numFaceVertices = 3; /* Edge has 3 vertices */
2486       break;
2487     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2488       *numFaceVertices = 3; /* Edge has 3 vertices */
2489       break;
2490     default:
2491       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2492     }
2493     break;
2494   case 3:
2495     switch (numCorners) {
2496     case 4: /* tetradehdron */
2497       *numFaceVertices = 3; /* Face has 3 vertices */
2498       break;
2499     case 6: /* tet cohesive cells */
2500       *numFaceVertices = 4; /* Face has 4 vertices */
2501       break;
2502     case 8: /* hexahedron */
2503       *numFaceVertices = 4; /* Face has 4 vertices */
2504       break;
2505     case 9: /* tet cohesive Lagrange cells */
2506       *numFaceVertices = 6; /* Face has 6 vertices */
2507       break;
2508     case 10: /* quadratic tetrahedron */
2509       *numFaceVertices = 6; /* Face has 6 vertices */
2510       break;
2511     case 12: /* hex cohesive Lagrange cells */
2512       *numFaceVertices = 6; /* Face has 6 vertices */
2513       break;
2514     case 18: /* quadratic tet cohesive Lagrange cells */
2515       *numFaceVertices = 6; /* Face has 6 vertices */
2516       break;
2517     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2518       *numFaceVertices = 9; /* Face has 9 vertices */
2519       break;
2520     default:
2521       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2522     }
2523     break;
2524   default:
2525     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2526   }
2527   PetscFunctionReturn(0);
2528 }
2529 
2530 #undef __FUNCT__
2531 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2532 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2533 {
2534   const PetscInt maxFaceCases = 30;
2535   PetscInt       numFaceCases = 0;
2536   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2537   PetscInt      *off, *adj;
2538   PetscInt      *neighborCells, *tmpClosure;
2539   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2540   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2541   PetscErrorCode ierr;
2542 
2543   PetscFunctionBegin;
2544   /* For parallel partitioning, I think you have to communicate supports */
2545   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2546   cellDim = dim - cellHeight;
2547   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2548   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2549   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2550   if (cEnd - cStart == 0) {
2551     if (numVertices) *numVertices = 0;
2552     if (offsets)   *offsets   = NULL;
2553     if (adjacency) *adjacency = NULL;
2554     PetscFunctionReturn(0);
2555   }
2556   numCells  = cEnd - cStart;
2557   faceDepth = depth - cellHeight;
2558   /* Setup face recognition */
2559   if (faceDepth == 1) {
2560     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 */
2561 
2562     for (c = cStart; c < cEnd; ++c) {
2563       PetscInt corners;
2564 
2565       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2566       if (!cornersSeen[corners]) {
2567         PetscInt nFV;
2568 
2569         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2570         cornersSeen[corners] = 1;
2571 
2572         ierr = DMPlexGetNumFaceVertices_Internal(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2573 
2574         numFaceVertices[numFaceCases++] = nFV;
2575       }
2576     }
2577   }
2578   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2579   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2580   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2581   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2582   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2583   /* Count neighboring cells */
2584   for (cell = cStart; cell < cEnd; ++cell) {
2585     PetscInt numNeighbors = maxNeighbors, n;
2586 
2587     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2588     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2589     for (n = 0; n < numNeighbors; ++n) {
2590       PetscInt        cellPair[2];
2591       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2592       PetscInt        meetSize = 0;
2593       const PetscInt *meet    = NULL;
2594 
2595       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2596       if (cellPair[0] == cellPair[1]) continue;
2597       if (!found) {
2598         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2599         if (meetSize) {
2600           PetscInt f;
2601 
2602           for (f = 0; f < numFaceCases; ++f) {
2603             if (numFaceVertices[f] == meetSize) {
2604               found = PETSC_TRUE;
2605               break;
2606             }
2607           }
2608         }
2609         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2610       }
2611       if (found) ++off[cell-cStart+1];
2612     }
2613   }
2614   /* Prefix sum */
2615   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2616 
2617   if (adjacency) {
2618     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2619     /* Get neighboring cells */
2620     for (cell = cStart; cell < cEnd; ++cell) {
2621       PetscInt numNeighbors = maxNeighbors, n;
2622       PetscInt cellOffset   = 0;
2623 
2624       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2625       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2626       for (n = 0; n < numNeighbors; ++n) {
2627         PetscInt        cellPair[2];
2628         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2629         PetscInt        meetSize = 0;
2630         const PetscInt *meet    = NULL;
2631 
2632         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2633         if (cellPair[0] == cellPair[1]) continue;
2634         if (!found) {
2635           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2636           if (meetSize) {
2637             PetscInt f;
2638 
2639             for (f = 0; f < numFaceCases; ++f) {
2640               if (numFaceVertices[f] == meetSize) {
2641                 found = PETSC_TRUE;
2642                 break;
2643               }
2644             }
2645           }
2646           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2647         }
2648         if (found) {
2649           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2650           ++cellOffset;
2651         }
2652       }
2653     }
2654   }
2655   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2656   if (numVertices) *numVertices = numCells;
2657   if (offsets)   *offsets   = off;
2658   if (adjacency) *adjacency = adj;
2659   PetscFunctionReturn(0);
2660 }
2661 
2662 #if defined(PETSC_HAVE_CHACO)
2663 #if defined(PETSC_HAVE_UNISTD_H)
2664 #include <unistd.h>
2665 #endif
2666 /* Chaco does not have an include file */
2667 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2668                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2669                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2670                        int mesh_dims[3], double *goal, int global_method, int local_method,
2671                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2672 
2673 extern int FREE_GRAPH;
2674 
2675 #undef __FUNCT__
2676 #define __FUNCT__ "DMPlexPartition_Chaco"
2677 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2678 {
2679   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2680   MPI_Comm       comm;
2681   int            nvtxs          = numVertices; /* number of vertices in full graph */
2682   int           *vwgts          = NULL;   /* weights for all vertices */
2683   float         *ewgts          = NULL;   /* weights for all edges */
2684   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2685   char          *outassignname  = NULL;   /*  name of assignment output file */
2686   char          *outfilename    = NULL;   /* output file name */
2687   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2688   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2689   int            mesh_dims[3];            /* dimensions of mesh of processors */
2690   double        *goal          = NULL;    /* desired set sizes for each set */
2691   int            global_method = 1;       /* global partitioning algorithm */
2692   int            local_method  = 1;       /* local partitioning algorithm */
2693   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2694   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2695   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2696   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2697   long           seed          = 123636512; /* for random graph mutations */
2698   short int     *assignment;              /* Output partition */
2699   int            fd_stdout, fd_pipe[2];
2700   PetscInt      *points;
2701   PetscMPIInt    commSize;
2702   int            i, v, p;
2703   PetscErrorCode ierr;
2704 
2705   PetscFunctionBegin;
2706   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2707   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2708   if (!numVertices) {
2709     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2710     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2711     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2712     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2713     PetscFunctionReturn(0);
2714   }
2715   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2716   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2717 
2718   if (global_method == INERTIAL_METHOD) {
2719     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2720     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2721   }
2722   mesh_dims[0] = commSize;
2723   mesh_dims[1] = 1;
2724   mesh_dims[2] = 1;
2725   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2726   /* Chaco outputs to stdout. We redirect this to a buffer. */
2727   /* TODO: check error codes for UNIX calls */
2728 #if defined(PETSC_HAVE_UNISTD_H)
2729   {
2730     int piperet;
2731     piperet = pipe(fd_pipe);
2732     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2733     fd_stdout = dup(1);
2734     close(1);
2735     dup2(fd_pipe[1], 1);
2736   }
2737 #endif
2738   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2739                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2740                    vmax, ndims, eigtol, seed);
2741 #if defined(PETSC_HAVE_UNISTD_H)
2742   {
2743     char msgLog[10000];
2744     int  count;
2745 
2746     fflush(stdout);
2747     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2748     if (count < 0) count = 0;
2749     msgLog[count] = 0;
2750     close(1);
2751     dup2(fd_stdout, 1);
2752     close(fd_stdout);
2753     close(fd_pipe[0]);
2754     close(fd_pipe[1]);
2755     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2756   }
2757 #endif
2758   /* Convert to PetscSection+IS */
2759   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2760   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2761   for (v = 0; v < nvtxs; ++v) {
2762     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2763   }
2764   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2765   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2766   for (p = 0, i = 0; p < commSize; ++p) {
2767     for (v = 0; v < nvtxs; ++v) {
2768       if (assignment[v] == p) points[i++] = v;
2769     }
2770   }
2771   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2772   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2773   if (global_method == INERTIAL_METHOD) {
2774     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2775   }
2776   ierr = PetscFree(assignment);CHKERRQ(ierr);
2777   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2778   PetscFunctionReturn(0);
2779 }
2780 #endif
2781 
2782 #if defined(PETSC_HAVE_PARMETIS)
2783 #undef __FUNCT__
2784 #define __FUNCT__ "DMPlexPartition_ParMetis"
2785 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2786 {
2787   PetscFunctionBegin;
2788   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2789   PetscFunctionReturn(0);
2790 }
2791 #endif
2792 
2793 #undef __FUNCT__
2794 #define __FUNCT__ "DMPlexEnlargePartition"
2795 /* Expand the partition by BFS on the adjacency graph */
2796 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2797 {
2798   PetscHashI      h;
2799   const PetscInt *points;
2800   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2801   PetscInt        pStart, pEnd, part, q;
2802   PetscErrorCode  ierr;
2803 
2804   PetscFunctionBegin;
2805   PetscHashICreate(h);
2806   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2807   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2808   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2809   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2810   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2811   for (part = pStart; part < pEnd; ++part) {
2812     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2813 
2814     PetscHashIClear(h);
2815     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2816     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2817     /* Add all existing points to h */
2818     for (p = 0; p < numPoints; ++p) {
2819       const PetscInt point = points[off+p];
2820       PetscHashIAdd(h, point, 1);
2821     }
2822     PetscHashISize(h, nP);
2823     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2824     /* Add all points in next BFS level */
2825     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2826     for (p = 0; p < numPoints; ++p) {
2827       const PetscInt point = points[off+p];
2828       PetscInt       s     = start[point], e = start[point+1], a;
2829 
2830       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2831     }
2832     PetscHashISize(h, numNewPoints);
2833     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2834     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2835     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2836     totPoints += numNewPoints;
2837   }
2838   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2839   PetscHashIDestroy(h);
2840   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2841   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2842   for (part = pStart, q = 0; part < pEnd; ++part) {
2843     PetscInt numPoints, p;
2844 
2845     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2846     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2847     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2848   }
2849   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2850   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2851   PetscFunctionReturn(0);
2852 }
2853 
2854 #undef __FUNCT__
2855 #define __FUNCT__ "DMPlexCreatePartition"
2856 /*
2857   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2858 
2859   Collective on DM
2860 
2861   Input Parameters:
2862   + dm - The DM
2863   . height - The height for points in the partition
2864   - enlarge - Expand each partition with neighbors
2865 
2866   Output Parameters:
2867   + partSection - The PetscSection giving the division of points by partition
2868   . partition - The list of points by partition
2869   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2870   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2871 
2872   Level: developer
2873 
2874 .seealso DMPlexDistribute()
2875 */
2876 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2877 {
2878   PetscMPIInt    size;
2879   PetscErrorCode ierr;
2880 
2881   PetscFunctionBegin;
2882   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2883 
2884   *origPartSection = NULL;
2885   *origPartition   = NULL;
2886   if (size == 1) {
2887     PetscInt *points;
2888     PetscInt  cStart, cEnd, c;
2889 
2890     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2891     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2892     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2893     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2894     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2895     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2896     for (c = cStart; c < cEnd; ++c) points[c] = c;
2897     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2898     PetscFunctionReturn(0);
2899   }
2900   if (height == 0) {
2901     PetscInt  numVertices;
2902     PetscInt *start     = NULL;
2903     PetscInt *adjacency = NULL;
2904 
2905     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2906     if (1) {
2907 #if defined(PETSC_HAVE_CHACO)
2908       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2909 #endif
2910     } else {
2911 #if defined(PETSC_HAVE_PARMETIS)
2912       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2913 #endif
2914     }
2915     if (enlarge) {
2916       *origPartSection = *partSection;
2917       *origPartition   = *partition;
2918 
2919       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2920     }
2921     ierr = PetscFree(start);CHKERRQ(ierr);
2922     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2923 # if 0
2924   } else if (height == 1) {
2925     /* Build the dual graph for faces and partition the hypergraph */
2926     PetscInt numEdges;
2927 
2928     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2929     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2930     destroyCSR(numEdges, start, adjacency);
2931 #endif
2932   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2933   PetscFunctionReturn(0);
2934 }
2935 
2936 #undef __FUNCT__
2937 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2938 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2939 {
2940   /* const PetscInt  height = 0; */
2941   const PetscInt *partArray;
2942   PetscInt       *allPoints, *partPoints = NULL;
2943   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2944   PetscErrorCode  ierr;
2945 
2946   PetscFunctionBegin;
2947   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2948   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2949   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2950   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2951   for (rank = rStart; rank < rEnd; ++rank) {
2952     PetscInt partSize = 0;
2953     PetscInt numPoints, offset, p;
2954 
2955     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2956     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2957     for (p = 0; p < numPoints; ++p) {
2958       PetscInt  point   = partArray[offset+p], closureSize, c;
2959       PetscInt *closure = NULL;
2960 
2961       /* TODO Include support for height > 0 case */
2962       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2963       /* Merge into existing points */
2964       if (partSize+closureSize > maxPartSize) {
2965         PetscInt *tmpPoints;
2966 
2967         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2968         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2969         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2970         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2971 
2972         partPoints = tmpPoints;
2973       }
2974       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
2975       partSize += closureSize;
2976 
2977       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2978       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2979     }
2980     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2981   }
2982   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2983   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2984   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2985 
2986   for (rank = rStart; rank < rEnd; ++rank) {
2987     PetscInt partSize = 0, newOffset;
2988     PetscInt numPoints, offset, p;
2989 
2990     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2991     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2992     for (p = 0; p < numPoints; ++p) {
2993       PetscInt  point   = partArray[offset+p], closureSize, c;
2994       PetscInt *closure = NULL;
2995 
2996       /* TODO Include support for height > 0 case */
2997       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2998       /* Merge into existing points */
2999       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3000       partSize += closureSize;
3001 
3002       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3003       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3004     }
3005     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3006     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3007   }
3008   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3009   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3010   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3011   PetscFunctionReturn(0);
3012 }
3013 
3014 #undef __FUNCT__
3015 #define __FUNCT__ "DMPlexDistributeField"
3016 /*
3017   Input Parameters:
3018 . originalSection
3019 , originalVec
3020 
3021   Output Parameters:
3022 . newSection
3023 . newVec
3024 */
3025 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3026 {
3027   PetscSF        fieldSF;
3028   PetscInt      *remoteOffsets, fieldSize;
3029   PetscScalar   *originalValues, *newValues;
3030   PetscErrorCode ierr;
3031 
3032   PetscFunctionBegin;
3033   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3034 
3035   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3036   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3037   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3038 
3039   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3040   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3041   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3042   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3043   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3044   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3045   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3046   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3047   PetscFunctionReturn(0);
3048 }
3049 
3050 #undef __FUNCT__
3051 #define __FUNCT__ "DMPlexDistribute"
3052 /*@C
3053   DMPlexDistribute - Distributes the mesh and any associated sections.
3054 
3055   Not Collective
3056 
3057   Input Parameter:
3058 + dm  - The original DMPlex object
3059 . partitioner - The partitioning package, or NULL for the default
3060 - overlap - The overlap of partitions, 0 is the default
3061 
3062   Output Parameter:
3063 . parallelMesh - The distributed DMPlex object, or NULL
3064 
3065   Note: If the mesh was not distributed, the return value is NULL
3066 
3067   Level: intermediate
3068 
3069 .keywords: mesh, elements
3070 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3071 @*/
3072 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3073 {
3074   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3075   MPI_Comm               comm;
3076   const PetscInt         height = 0;
3077   PetscInt               dim, numRemoteRanks;
3078   IS                     origCellPart,        cellPart,        part;
3079   PetscSection           origCellPartSection, cellPartSection, partSection;
3080   PetscSFNode           *remoteRanks;
3081   PetscSF                partSF, pointSF, coneSF;
3082   ISLocalToGlobalMapping renumbering;
3083   PetscSection           originalConeSection, newConeSection;
3084   PetscInt              *remoteOffsets;
3085   PetscInt              *cones, *newCones, newConesSize;
3086   PetscBool              flg;
3087   PetscMPIInt            rank, numProcs, p;
3088   PetscErrorCode         ierr;
3089 
3090   PetscFunctionBegin;
3091   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3092   PetscValidPointer(dmParallel,4);
3093 
3094   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3095   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3096   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3097   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3098 
3099   *dmParallel = NULL;
3100   if (numProcs == 1) PetscFunctionReturn(0);
3101 
3102   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3103   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3104   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3105   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3106   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3107   if (!rank) numRemoteRanks = numProcs;
3108   else       numRemoteRanks = 0;
3109   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3110   for (p = 0; p < numRemoteRanks; ++p) {
3111     remoteRanks[p].rank  = p;
3112     remoteRanks[p].index = 0;
3113   }
3114   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3115   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3116   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3117   if (flg) {
3118     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3119     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3120     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3121     if (origCellPart) {
3122       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3123       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3124       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3125     }
3126     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3127   }
3128   /* Close the partition over the mesh */
3129   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3130   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3131   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3132   /* Create new mesh */
3133   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3134   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3135   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3136   pmesh = (DM_Plex*) (*dmParallel)->data;
3137   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3138   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3139   if (flg) {
3140     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3141     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3142     ierr = ISView(part, NULL);CHKERRQ(ierr);
3143     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3144     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3145     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3146   }
3147   /* Distribute cone section */
3148   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3149   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3150   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3151   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3152   {
3153     PetscInt pStart, pEnd, p;
3154 
3155     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3156     for (p = pStart; p < pEnd; ++p) {
3157       PetscInt coneSize;
3158       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3159       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3160     }
3161   }
3162   /* Communicate and renumber cones */
3163   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3164   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3165   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3166   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3167   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3168   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3169   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3170   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3171   if (flg) {
3172     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3173     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3174     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3175     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3176     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3177   }
3178   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3179   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3180   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3181   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3182   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3183   /* Create supports and stratify sieve */
3184   {
3185     PetscInt pStart, pEnd;
3186 
3187     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3188     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3189   }
3190   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3191   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3192   /* Distribute Coordinates */
3193   {
3194     PetscSection originalCoordSection, newCoordSection;
3195     Vec          originalCoordinates, newCoordinates;
3196     const char  *name;
3197 
3198     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3199     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3200     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3201     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3202     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3203     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3204 
3205     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3206     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3207     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3208   }
3209   /* Distribute labels */
3210   {
3211     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3212     PetscInt numLabels = 0, l;
3213 
3214     /* Bcast number of labels */
3215     while (next) {
3216       ++numLabels; next = next->next;
3217     }
3218     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3219     next = mesh->labels;
3220     for (l = 0; l < numLabels; ++l) {
3221       DMLabel         newLabel;
3222       const PetscInt *partArray;
3223       char           *name;
3224       PetscInt       *stratumSizes = NULL, *points = NULL;
3225       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3226       PetscInt        nameSize, s, p;
3227       PetscBool       isdepth;
3228       size_t          len = 0;
3229 
3230       /* Bcast name (could filter for no points) */
3231       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3232       nameSize = len;
3233       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3234       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3235       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3236       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3237       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3238       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3239       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3240       newLabel->name = name;
3241       /* Bcast numStrata (could filter for no points in stratum) */
3242       if (!rank) newLabel->numStrata = next->numStrata;
3243       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3244       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3245                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3246                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3247       /* Bcast stratumValues (could filter for no points in stratum) */
3248       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3249       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3250       /* Find size on each process and Scatter */
3251       if (!rank) {
3252         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3253         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3254         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3255         for (s = 0; s < next->numStrata; ++s) {
3256           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3257             const PetscInt point = next->points[p];
3258             PetscInt       proc;
3259 
3260             for (proc = 0; proc < numProcs; ++proc) {
3261               PetscInt dof, off, pPart;
3262 
3263               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3264               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3265               for (pPart = off; pPart < off+dof; ++pPart) {
3266                 if (partArray[pPart] == point) {
3267                   ++stratumSizes[proc*next->numStrata+s];
3268                   break;
3269                 }
3270               }
3271             }
3272           }
3273         }
3274         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3275       }
3276       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3277       /* Calculate stratumOffsets */
3278       newLabel->stratumOffsets[0] = 0;
3279       for (s = 0; s < newLabel->numStrata; ++s) {
3280         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3281       }
3282       /* Pack points and Scatter */
3283       if (!rank) {
3284         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3285         displs[0] = 0;
3286         for (p = 0; p < numProcs; ++p) {
3287           sendcnts[p] = 0;
3288           for (s = 0; s < next->numStrata; ++s) {
3289             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3290           }
3291           offsets[p]  = displs[p];
3292           displs[p+1] = displs[p] + sendcnts[p];
3293         }
3294         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3295         for (s = 0; s < next->numStrata; ++s) {
3296           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3297             const PetscInt point = next->points[p];
3298             PetscInt       proc;
3299 
3300             for (proc = 0; proc < numProcs; ++proc) {
3301               PetscInt dof, off, pPart;
3302 
3303               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3304               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3305               for (pPart = off; pPart < off+dof; ++pPart) {
3306                 if (partArray[pPart] == point) {
3307                   points[offsets[proc]++] = point;
3308                   break;
3309                 }
3310               }
3311             }
3312           }
3313         }
3314       }
3315       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3316       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3317       ierr = PetscFree(points);CHKERRQ(ierr);
3318       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3319       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3320       /* Renumber points */
3321       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3322       /* Sort points */
3323       for (s = 0; s < newLabel->numStrata; ++s) {
3324         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3325       }
3326       /* Insert into list */
3327       if (newNext) newNext->next = newLabel;
3328       else pmesh->labels = newLabel;
3329       newNext = newLabel;
3330       if (!rank) next = next->next;
3331     }
3332   }
3333   /* Cleanup Partition */
3334   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3335   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3336   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3337   ierr = ISDestroy(&part);CHKERRQ(ierr);
3338   /* Create point SF for parallel mesh */
3339   {
3340     const PetscInt *leaves;
3341     PetscSFNode    *remotePoints, *rowners, *lowners;
3342     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3343     PetscInt        pStart, pEnd;
3344 
3345     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3346     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3347     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3348     for (p=0; p<numRoots; p++) {
3349       rowners[p].rank  = -1;
3350       rowners[p].index = -1;
3351     }
3352     if (origCellPart) {
3353       /* Make sure cells in the original partition are not assigned to other procs */
3354       const PetscInt *origCells;
3355 
3356       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3357       for (p = 0; p < numProcs; ++p) {
3358         PetscInt dof, off, d;
3359 
3360         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3361         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3362         for (d = off; d < off+dof; ++d) {
3363           rowners[origCells[d]].rank = p;
3364         }
3365       }
3366       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3367     }
3368     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3369     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3370 
3371     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3372     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3373     for (p = 0; p < numLeaves; ++p) {
3374       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3375         lowners[p].rank  = rank;
3376         lowners[p].index = leaves ? leaves[p] : p;
3377       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3378         lowners[p].rank  = -2;
3379         lowners[p].index = -2;
3380       }
3381     }
3382     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3383       rowners[p].rank  = -3;
3384       rowners[p].index = -3;
3385     }
3386     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3387     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3388     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3389     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3390     for (p = 0; p < numLeaves; ++p) {
3391       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3392       if (lowners[p].rank != rank) ++numGhostPoints;
3393     }
3394     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3395     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3396     for (p = 0, gp = 0; p < numLeaves; ++p) {
3397       if (lowners[p].rank != rank) {
3398         ghostPoints[gp]        = leaves ? leaves[p] : p;
3399         remotePoints[gp].rank  = lowners[p].rank;
3400         remotePoints[gp].index = lowners[p].index;
3401         ++gp;
3402       }
3403     }
3404     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3405     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3406     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3407   }
3408   /* Cleanup */
3409   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3410   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3411   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3412   PetscFunctionReturn(0);
3413 }
3414 
3415 #undef __FUNCT__
3416 #define __FUNCT__ "DMPlexRenumber_Private"
3417 /*
3418   Reasons to renumber:
3419 
3420   1) Permute points, e.g. bandwidth reduction (Renumber)
3421 
3422     a) Must not mix strata
3423 
3424   2) Shift numbers for point insertion (Shift)
3425 
3426     a) Want operation brken into parts so that insertion can be interleaved
3427 
3428   renumbering - An IS which provides the new numbering
3429 */
3430 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3431 {
3432   PetscFunctionBegin;
3433   PetscFunctionReturn(0);
3434 }
3435 
3436 #undef __FUNCT__
3437 #define __FUNCT__ "DMPlexShiftPoint_Private"
3438 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3439 {
3440   if (depth < 0) return p;
3441   /* Cells    */ if (p < depthEnd[depth])   return p;
3442   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3443   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3444   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3445 }
3446 
3447 #undef __FUNCT__
3448 #define __FUNCT__ "DMPlexShiftSizes_Private"
3449 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3450 {
3451   PetscInt      *depthEnd;
3452   PetscInt       depth = 0, d, pStart, pEnd, p;
3453   PetscErrorCode ierr;
3454 
3455   PetscFunctionBegin;
3456   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3457   if (depth < 0) PetscFunctionReturn(0);
3458   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3459   /* Step 1: Expand chart */
3460   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3461   for (d = 0; d <= depth; ++d) {
3462     pEnd += depthShift[d];
3463     ierr  = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3464   }
3465   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3466   /* Step 2: Set cone and support sizes */
3467   for (d = 0; d <= depth; ++d) {
3468     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3469     for (p = pStart; p < pEnd; ++p) {
3470       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3471       PetscInt size;
3472 
3473       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3474       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3475       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3476       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3477     }
3478   }
3479   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3480   PetscFunctionReturn(0);
3481 }
3482 
3483 #undef __FUNCT__
3484 #define __FUNCT__ "DMPlexShiftPoints_Private"
3485 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3486 {
3487   PetscInt      *depthEnd, *newpoints;
3488   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3489   PetscErrorCode ierr;
3490 
3491   PetscFunctionBegin;
3492   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3493   if (depth < 0) PetscFunctionReturn(0);
3494   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3495   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3496   for (d = 0; d <= depth; ++d) {
3497     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3498   }
3499   /* Step 5: Set cones and supports */
3500   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3501   for (p = pStart; p < pEnd; ++p) {
3502     const PetscInt *points = NULL, *orientations = NULL;
3503     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3504 
3505     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3506     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3507     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3508     for (i = 0; i < size; ++i) {
3509       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3510     }
3511     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3512     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3513     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3514     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3515     for (i = 0; i < size; ++i) {
3516       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3517     }
3518     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3519   }
3520   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3521   PetscFunctionReturn(0);
3522 }
3523 
3524 #undef __FUNCT__
3525 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3526 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3527 {
3528   PetscSection   coordSection, newCoordSection;
3529   Vec            coordinates, newCoordinates;
3530   PetscScalar   *coords, *newCoords;
3531   PetscInt      *depthEnd, coordSize;
3532   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3533   PetscErrorCode ierr;
3534 
3535   PetscFunctionBegin;
3536   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3537   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3538   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3539   for (d = 0; d <= depth; ++d) {
3540     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3541   }
3542   /* Step 8: Convert coordinates */
3543   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3544   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3545   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3546   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection);CHKERRQ(ierr);
3547   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3548   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3549   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3550   for (v = vStartNew; v < vEndNew; ++v) {
3551     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3552     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3553   }
3554   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3555   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3556   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3557   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &newCoordinates);CHKERRQ(ierr);
3558   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3559   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3560   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3561   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3562   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3563   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3564   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3565   for (v = vStart; v < vEnd; ++v) {
3566     PetscInt dof, off, noff, d;
3567 
3568     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3569     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3570     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3571     for (d = 0; d < dof; ++d) {
3572       newCoords[noff+d] = coords[off+d];
3573     }
3574   }
3575   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3576   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3577   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3578   ierr = PetscSectionDestroy(&newCoordSection);CHKERRQ(ierr);
3579   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3580   PetscFunctionReturn(0);
3581 }
3582 
3583 #undef __FUNCT__
3584 #define __FUNCT__ "DMPlexShiftSF_Private"
3585 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3586 {
3587   PetscInt          *depthEnd;
3588   PetscInt           depth = 0, d;
3589   PetscSF            sfPoint, sfPointNew;
3590   const PetscSFNode *remotePoints;
3591   PetscSFNode       *gremotePoints;
3592   const PetscInt    *localPoints;
3593   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3594   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3595   PetscMPIInt        numProcs;
3596   PetscErrorCode     ierr;
3597 
3598   PetscFunctionBegin;
3599   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3600   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3601   for (d = 0; d <= depth; ++d) {
3602     totShift += depthShift[d];
3603     ierr      = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3604   }
3605   /* Step 9: Convert pointSF */
3606   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
3607   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3608   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3609   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3610   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3611   if (numRoots >= 0) {
3612     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3613     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3614     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3615     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3616     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3617     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3618     for (l = 0; l < numLeaves; ++l) {
3619       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3620       gremotePoints[l].rank  = remotePoints[l].rank;
3621       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3622     }
3623     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3624     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3625   }
3626   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3627   PetscFunctionReturn(0);
3628 }
3629 
3630 #undef __FUNCT__
3631 #define __FUNCT__ "DMPlexShiftLabels_Private"
3632 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3633 {
3634   PetscSF            sfPoint;
3635   DMLabel            vtkLabel, ghostLabel;
3636   PetscInt          *depthEnd;
3637   const PetscSFNode *leafRemote;
3638   const PetscInt    *leafLocal;
3639   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3640   PetscMPIInt        rank;
3641   PetscErrorCode     ierr;
3642 
3643   PetscFunctionBegin;
3644   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3645   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3646   for (d = 0; d <= depth; ++d) {
3647     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3648   }
3649   /* Step 10: Convert labels */
3650   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3651   for (l = 0; l < numLabels; ++l) {
3652     DMLabel         label, newlabel;
3653     const char     *lname;
3654     PetscBool       isDepth;
3655     IS              valueIS;
3656     const PetscInt *values;
3657     PetscInt        numValues, val;
3658 
3659     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3660     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3661     if (isDepth) continue;
3662     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3663     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3664     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3665     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3666     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3667     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3668     for (val = 0; val < numValues; ++val) {
3669       IS              pointIS;
3670       const PetscInt *points;
3671       PetscInt        numPoints, p;
3672 
3673       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3674       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3675       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3676       for (p = 0; p < numPoints; ++p) {
3677         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3678 
3679         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3680       }
3681       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3682       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3683     }
3684     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3685     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3686   }
3687   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3688   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3689   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
3690   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3691   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3692   ierr = PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3693   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3694   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3695   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3696   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3697   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3698     for (; c < leafLocal[l] && c < cEnd; ++c) {
3699       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3700     }
3701     if (leafLocal[l] >= cEnd) break;
3702     if (leafRemote[l].rank == rank) {
3703       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3704     } else {
3705       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3706     }
3707   }
3708   for (; c < cEnd; ++c) {
3709     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3710   }
3711   if (0) {
3712     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3713     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3714     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3715   }
3716   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3717   for (f = fStart; f < fEnd; ++f) {
3718     PetscInt numCells;
3719 
3720     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3721     if (numCells < 2) {
3722       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3723     } else {
3724       const PetscInt *cells = NULL;
3725       PetscInt        vA, vB;
3726 
3727       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3728       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3729       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3730       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3731     }
3732   }
3733   if (0) {
3734     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3735     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3736     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3737   }
3738   PetscFunctionReturn(0);
3739 }
3740 
3741 #undef __FUNCT__
3742 #define __FUNCT__ "DMPlexConstructGhostCells_Internal"
3743 static PetscErrorCode DMPlexConstructGhostCells_Internal(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3744 {
3745   DMLabel         label;
3746   IS              valueIS;
3747   const PetscInt *values;
3748   PetscInt       *depthShift;
3749   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3750   PetscErrorCode  ierr;
3751 
3752   PetscFunctionBegin;
3753   /* Count ghost cells */
3754   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3755   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3756   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3757   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3758 
3759   *numGhostCells = 0;
3760   for (fs = 0; fs < numFS; ++fs) {
3761     PetscInt numBdFaces;
3762 
3763     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3764 
3765     *numGhostCells += numBdFaces;
3766   }
3767   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3768   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3769   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3770   if (depth >= 0) depthShift[depth] = *numGhostCells;
3771   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3772   /* Step 3: Set cone/support sizes for new points */
3773   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
3774   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3775     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3776   }
3777   for (fs = 0; fs < numFS; ++fs) {
3778     IS              faceIS;
3779     const PetscInt *faces;
3780     PetscInt        numFaces, f;
3781 
3782     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3783     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3784     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3785     for (f = 0; f < numFaces; ++f) {
3786       PetscInt size;
3787 
3788       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3789       if (size != 1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3790       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3791     }
3792     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3793     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3794   }
3795   /* Step 4: Setup ghosted DM */
3796   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3797   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3798   /* Step 6: Set cones and supports for new points */
3799   ghostCell = cEnd;
3800   for (fs = 0; fs < numFS; ++fs) {
3801     IS              faceIS;
3802     const PetscInt *faces;
3803     PetscInt        numFaces, f;
3804 
3805     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3806     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3807     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3808     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3809       PetscInt newFace = faces[f] + *numGhostCells;
3810 
3811       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3812       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3813     }
3814     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3815     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3816   }
3817   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3818   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3819   /* Step 7: Stratify */
3820   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3821   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3822   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3823   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3824   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3825   PetscFunctionReturn(0);
3826 }
3827 
3828 #undef __FUNCT__
3829 #define __FUNCT__ "DMPlexConstructGhostCells"
3830 /*@C
3831   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3832 
3833   Collective on dm
3834 
3835   Input Parameters:
3836 + dm - The original DM
3837 - labelName - The label specifying the boundary faces, or "Face Sets" if this is NULL
3838 
3839   Output Parameters:
3840 + numGhostCells - The number of ghost cells added to the DM
3841 - dmGhosted - The new DM
3842 
3843   Level: developer
3844 
3845 .seealso: DMCreate()
3846 */
3847 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3848 {
3849   DM             gdm;
3850   PetscInt       dim;
3851   PetscErrorCode ierr;
3852 
3853   PetscFunctionBegin;
3854   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3855   PetscValidPointer(numGhostCells, 3);
3856   PetscValidPointer(dmGhosted, 4);
3857   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &gdm);CHKERRQ(ierr);
3858   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3859   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3860   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3861   ierr = DMPlexConstructGhostCells_Internal(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3862   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3863   *dmGhosted = gdm;
3864   PetscFunctionReturn(0);
3865 }
3866 
3867 #undef __FUNCT__
3868 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3869 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3870 {
3871   MPI_Comm        comm;
3872   IS              valueIS, *pointIS;
3873   const PetscInt *values, **splitPoints;
3874   PetscSection    coordSection;
3875   Vec             coordinates;
3876   PetscScalar    *coords;
3877   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3878   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3879   PetscErrorCode  ierr;
3880 
3881   PetscFunctionBegin;
3882   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3883   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3884   /* Count split points and add cohesive cells */
3885   if (label) {
3886     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3887     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3888     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3889   }
3890   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3891   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3892   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3893   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3894   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3895   for (d = 0; d <= depth; ++d) {
3896     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3897     numSplitPoints[d] = 0;
3898     splitPoints[d]    = NULL;
3899     pointIS[d]        = NULL;
3900   }
3901   for (sp = 0; sp < numSP; ++sp) {
3902     const PetscInt dep = values[sp];
3903 
3904     if ((dep < 0) || (dep > depth)) continue;
3905     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3906     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3907     if (pointIS[dep]) {
3908       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3909       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3910     }
3911   }
3912   if (depth >= 0) {
3913     /* Calculate number of additional points */
3914     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3915     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3916     /* Calculate hybrid bound for each dimension */
3917     pMaxNew[0] += depthShift[depth];
3918     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3919     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3920 
3921     /* Calculate point offset for each dimension */
3922     depthOffset[depth] = 0;
3923     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3924     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3925     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3926   }
3927   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3928   /* Step 3: Set cone/support sizes for new points */
3929   for (dep = 0; dep <= depth; ++dep) {
3930     for (p = 0; p < numSplitPoints[dep]; ++p) {
3931       const PetscInt  oldp   = splitPoints[dep][p];
3932       const PetscInt  newp   = depthOffset[dep] + oldp;
3933       const PetscInt  splitp = pMaxNew[dep] + p;
3934       const PetscInt *support;
3935       PetscInt        coneSize, supportSize, q, e;
3936 
3937       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3938       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3939       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3940       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3941       if (dep == depth-1) {
3942         const PetscInt ccell = pMaxNew[depth] + p;
3943         /* Add cohesive cells, they are prisms */
3944         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3945       } else if (dep == 0) {
3946         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3947 
3948         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3949         /* Split old vertex: Edges in old split faces and new cohesive edge */
3950         for (e = 0, q = 0; e < supportSize; ++e) {
3951           PetscInt val;
3952 
3953           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3954           if ((val == 1) || (val == (shift + 1))) ++q;
3955         }
3956         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3957         /* Split new vertex: Edges in new split faces and new cohesive edge */
3958         for (e = 0, q = 0; e < supportSize; ++e) {
3959           PetscInt val;
3960 
3961           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3962           if ((val == 1) || (val == -(shift + 1))) ++q;
3963         }
3964         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
3965         /* Add cohesive edges */
3966         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
3967         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3968       } else if (dep == dim-2) {
3969         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3970         /* Split old edge: Faces in positive side cells and old split faces */
3971         for (e = 0, q = 0; e < supportSize; ++e) {
3972           PetscInt val;
3973 
3974           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3975           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
3976         }
3977         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
3978         /* Split new edge: Faces in negative side cells and new split faces */
3979         for (e = 0, q = 0; e < supportSize; ++e) {
3980           PetscInt val;
3981 
3982           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3983           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
3984         }
3985         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
3986       }
3987     }
3988   }
3989   /* Step 4: Setup split DM */
3990   ierr = DMSetUp(sdm);CHKERRQ(ierr);
3991   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3992   /* Step 6: Set cones and supports for new points */
3993   for (dep = 0; dep <= depth; ++dep) {
3994     for (p = 0; p < numSplitPoints[dep]; ++p) {
3995       const PetscInt  oldp   = splitPoints[dep][p];
3996       const PetscInt  newp   = depthOffset[dep] + oldp;
3997       const PetscInt  splitp = pMaxNew[dep] + p;
3998       const PetscInt *cone, *support, *ornt;
3999       PetscInt        coneSize, supportSize, q, v, e, s;
4000 
4001       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4002       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4003       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4004       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4005       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4006       if (dep == depth-1) {
4007         const PetscInt  ccell = pMaxNew[depth] + p;
4008         const PetscInt *supportF;
4009 
4010         /* Split face:       copy in old face to new face to start */
4011         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4012         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4013         /* Split old face:   old vertices/edges in cone so no change */
4014         /* Split new face:   new vertices/edges in cone */
4015         for (q = 0; q < coneSize; ++q) {
4016           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4017 
4018           coneNew[2+q] = pMaxNew[dim-2] + v;
4019         }
4020         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4021         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4022         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4023         coneNew[0] = newp;
4024         coneNew[1] = splitp;
4025         for (q = 0; q < coneSize; ++q) {
4026           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4027         }
4028         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4029 
4030 
4031         for (s = 0; s < supportSize; ++s) {
4032           PetscInt val;
4033 
4034           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4035           if (val < 0) {
4036             /* Split old face:   Replace negative side cell with cohesive cell */
4037             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4038           } else {
4039             /* Split new face:   Replace positive side cell with cohesive cell */
4040             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4041           }
4042         }
4043       } else if (dep == 0) {
4044         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4045 
4046         /* Split old vertex: Edges in old split faces and new cohesive edge */
4047         for (e = 0, q = 0; e < supportSize; ++e) {
4048           PetscInt val;
4049 
4050           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4051           if ((val == 1) || (val == (shift + 1))) {
4052             supportNew[q++] = depthOffset[1] + support[e];
4053           }
4054         }
4055         supportNew[q] = cedge;
4056 
4057         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4058         /* Split new vertex: Edges in new split faces and new cohesive edge */
4059         for (e = 0, q = 0; e < supportSize; ++e) {
4060           PetscInt val, edge;
4061 
4062           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4063           if (val == 1) {
4064             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4065             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4066             supportNew[q++] = pMaxNew[1] + edge;
4067           } else if (val == -(shift + 1)) {
4068             supportNew[q++] = depthOffset[1] + support[e];
4069           }
4070         }
4071         supportNew[q] = cedge;
4072         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4073         /* Cohesive edge:    Old and new split vertex, punting on support */
4074         coneNew[0] = newp;
4075         coneNew[1] = splitp;
4076         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4077       } else if (dep == dim-2) {
4078         /* Split old edge:   old vertices in cone so no change */
4079         /* Split new edge:   new vertices in cone */
4080         for (q = 0; q < coneSize; ++q) {
4081           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4082 
4083           coneNew[q] = pMaxNew[dim-3] + v;
4084         }
4085         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4086         /* Split old edge: Faces in positive side cells and old split faces */
4087         for (e = 0, q = 0; e < supportSize; ++e) {
4088           PetscInt val;
4089 
4090           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4091           if ((val == dim-1) || (val == (shift + dim-1))) {
4092             supportNew[q++] = depthOffset[dim-1] + support[e];
4093           }
4094         }
4095         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4096         /* Split new edge: Faces in negative side cells and new split faces */
4097         for (e = 0, q = 0; e < supportSize; ++e) {
4098           PetscInt val, face;
4099 
4100           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4101           if (val == dim-1) {
4102             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4103             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4104             supportNew[q++] = pMaxNew[dim-1] + face;
4105           } else if (val == -(shift + dim-1)) {
4106             supportNew[q++] = depthOffset[dim-1] + support[e];
4107           }
4108         }
4109         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4110       }
4111     }
4112   }
4113   /* Step 6b: Replace split points in negative side cones */
4114   for (sp = 0; sp < numSP; ++sp) {
4115     PetscInt        dep = values[sp];
4116     IS              pIS;
4117     PetscInt        numPoints;
4118     const PetscInt *points;
4119 
4120     if (dep >= 0) continue;
4121     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4122     if (!pIS) continue;
4123     dep  = -dep - shift;
4124     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4125     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4126     for (p = 0; p < numPoints; ++p) {
4127       const PetscInt  oldp = points[p];
4128       const PetscInt  newp = depthOffset[dep] + oldp;
4129       const PetscInt *cone;
4130       PetscInt        coneSize, c;
4131       PetscBool       replaced = PETSC_FALSE;
4132 
4133       /* Negative edge: replace split vertex */
4134       /* Negative cell: replace split face */
4135       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4136       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4137       for (c = 0; c < coneSize; ++c) {
4138         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4139         PetscInt       csplitp, cp, val;
4140 
4141         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4142         if (val == dep-1) {
4143           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4144           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4145           csplitp  = pMaxNew[dep-1] + cp;
4146           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4147           replaced = PETSC_TRUE;
4148         }
4149       }
4150       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4151     }
4152     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4153     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4154   }
4155   /* Step 7: Stratify */
4156   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4157   /* Step 8: Coordinates */
4158   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4159   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4160   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4161   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4162   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4163     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4164     const PetscInt splitp = pMaxNew[0] + v;
4165     PetscInt       dof, off, soff, d;
4166 
4167     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4168     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4169     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4170     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4171   }
4172   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4173   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4174   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4175   /* Step 10: Labels */
4176   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4177   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4178   for (dep = 0; dep <= depth; ++dep) {
4179     for (p = 0; p < numSplitPoints[dep]; ++p) {
4180       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4181       const PetscInt splitp = pMaxNew[dep] + p;
4182       PetscInt       l;
4183 
4184       for (l = 0; l < numLabels; ++l) {
4185         DMLabel     mlabel;
4186         const char *lname;
4187         PetscInt    val;
4188 
4189         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4190         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4191         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4192         if (val >= 0) {
4193           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4194           if (dep == 0) {
4195             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4196             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4197           }
4198         }
4199       }
4200     }
4201   }
4202   for (sp = 0; sp < numSP; ++sp) {
4203     const PetscInt dep = values[sp];
4204 
4205     if ((dep < 0) || (dep > depth)) continue;
4206     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4207     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4208   }
4209   if (label) {
4210     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4211     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4212   }
4213   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4214   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4215   PetscFunctionReturn(0);
4216 }
4217 
4218 #undef __FUNCT__
4219 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4220 /*@C
4221   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4222 
4223   Collective on dm
4224 
4225   Input Parameters:
4226 + dm - The original DM
4227 - labelName - The label specifying the boundary faces (this could be auto-generated)
4228 
4229   Output Parameters:
4230 - dmSplit - The new DM
4231 
4232   Level: developer
4233 
4234 .seealso: DMCreate()
4235 */
4236 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4237 {
4238   DM             sdm;
4239   PetscInt       dim;
4240   PetscErrorCode ierr;
4241 
4242   PetscFunctionBegin;
4243   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4244   PetscValidPointer(dmSplit, 4);
4245   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &sdm);CHKERRQ(ierr);
4246   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4247   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4248   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4249   switch (dim) {
4250   case 2:
4251   case 3:
4252     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4253     break;
4254   default:
4255     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4256   }
4257   *dmSplit = sdm;
4258   PetscFunctionReturn(0);
4259 }
4260 
4261 #undef __FUNCT__
4262 #define __FUNCT__ "DMLabelCohesiveComplete"
4263 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4264 {
4265   IS              dimIS;
4266   const PetscInt *points;
4267   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4268   PetscErrorCode  ierr;
4269 
4270   PetscFunctionBegin;
4271   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4272   /* Cell orientation for face gives the side of the fault */
4273   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4274   if (!dimIS) PetscFunctionReturn(0);
4275   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4276   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4277   for (p = 0; p < numPoints; ++p) {
4278     const PetscInt *support;
4279     PetscInt        supportSize, s;
4280 
4281     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4282     if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4283     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4284     for (s = 0; s < supportSize; ++s) {
4285       const PetscInt *cone, *ornt;
4286       PetscInt        coneSize, c;
4287       PetscBool       pos = PETSC_TRUE;
4288 
4289       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4290       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4291       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4292       for (c = 0; c < coneSize; ++c) {
4293         if (cone[c] == points[p]) {
4294           if (ornt[c] >= 0) {
4295             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4296           } else {
4297             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4298             pos  = PETSC_FALSE;
4299           }
4300           break;
4301         }
4302       }
4303       if (c == coneSize) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4304       /* Put faces touching the fault in the label */
4305       for (c = 0; c < coneSize; ++c) {
4306         const PetscInt point = cone[c];
4307 
4308         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4309         if (val == -1) {
4310           PetscInt *closure = NULL;
4311           PetscInt  closureSize, cl;
4312 
4313           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4314           for (cl = 0; cl < closureSize*2; cl += 2) {
4315             const PetscInt clp = closure[cl];
4316 
4317             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4318             if ((val >= 0) && (val < dim-1)) {
4319               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4320               break;
4321             }
4322           }
4323           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4324         }
4325       }
4326     }
4327   }
4328   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4329   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4330   /* Search for other cells/faces/edges connected to the fault by a vertex */
4331   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4332   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4333   if (!dimIS) PetscFunctionReturn(0);
4334   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4335   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4336   for (p = 0; p < numPoints; ++p) {
4337     PetscInt *star = NULL;
4338     PetscInt  starSize, s;
4339     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4340 
4341     /* First mark cells connected to the fault */
4342     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4343     while (again) {
4344       if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4345       again = 0;
4346       for (s = 0; s < starSize*2; s += 2) {
4347         const PetscInt  point = star[s];
4348         const PetscInt *cone;
4349         PetscInt        coneSize, c;
4350 
4351         if ((point < cStart) || (point >= cEnd)) continue;
4352         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4353         if (val != -1) continue;
4354         again = 2;
4355         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4356         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4357         for (c = 0; c < coneSize; ++c) {
4358           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4359           if (val != -1) {
4360             if (abs(val) < shift) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4361             if (val > 0) {
4362               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4363             } else {
4364               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4365             }
4366             again = 1;
4367             break;
4368           }
4369         }
4370       }
4371     }
4372     /* Classify the rest by cell membership */
4373     for (s = 0; s < starSize*2; s += 2) {
4374       const PetscInt point = star[s];
4375 
4376       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4377       if (val == -1) {
4378         PetscInt  *sstar = NULL;
4379         PetscInt   sstarSize, ss;
4380         PetscBool  marked = PETSC_FALSE;
4381 
4382         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4383         for (ss = 0; ss < sstarSize*2; ss += 2) {
4384           const PetscInt spoint = sstar[ss];
4385 
4386           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4387           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4388           if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4389           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4390           if (val > 0) {
4391             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4392           } else {
4393             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4394           }
4395           marked = PETSC_TRUE;
4396           break;
4397         }
4398         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4399         if (!marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
4400       }
4401     }
4402     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4403   }
4404   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4405   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4406   PetscFunctionReturn(0);
4407 }
4408 
4409 #if defined(PETSC_HAVE_TRIANGLE)
4410 #include <triangle.h>
4411 
4412 #undef __FUNCT__
4413 #define __FUNCT__ "InitInput_Triangle"
4414 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4415 {
4416   PetscFunctionBegin;
4417   inputCtx->numberofpoints             = 0;
4418   inputCtx->numberofpointattributes    = 0;
4419   inputCtx->pointlist                  = NULL;
4420   inputCtx->pointattributelist         = NULL;
4421   inputCtx->pointmarkerlist            = NULL;
4422   inputCtx->numberofsegments           = 0;
4423   inputCtx->segmentlist                = NULL;
4424   inputCtx->segmentmarkerlist          = NULL;
4425   inputCtx->numberoftriangleattributes = 0;
4426   inputCtx->trianglelist               = NULL;
4427   inputCtx->numberofholes              = 0;
4428   inputCtx->holelist                   = NULL;
4429   inputCtx->numberofregions            = 0;
4430   inputCtx->regionlist                 = NULL;
4431   PetscFunctionReturn(0);
4432 }
4433 
4434 #undef __FUNCT__
4435 #define __FUNCT__ "InitOutput_Triangle"
4436 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4437 {
4438   PetscFunctionBegin;
4439   outputCtx->numberofpoints        = 0;
4440   outputCtx->pointlist             = NULL;
4441   outputCtx->pointattributelist    = NULL;
4442   outputCtx->pointmarkerlist       = NULL;
4443   outputCtx->numberoftriangles     = 0;
4444   outputCtx->trianglelist          = NULL;
4445   outputCtx->triangleattributelist = NULL;
4446   outputCtx->neighborlist          = NULL;
4447   outputCtx->segmentlist           = NULL;
4448   outputCtx->segmentmarkerlist     = NULL;
4449   outputCtx->numberofedges         = 0;
4450   outputCtx->edgelist              = NULL;
4451   outputCtx->edgemarkerlist        = NULL;
4452   PetscFunctionReturn(0);
4453 }
4454 
4455 #undef __FUNCT__
4456 #define __FUNCT__ "FiniOutput_Triangle"
4457 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4458 {
4459   PetscFunctionBegin;
4460   free(outputCtx->pointmarkerlist);
4461   free(outputCtx->edgelist);
4462   free(outputCtx->edgemarkerlist);
4463   free(outputCtx->trianglelist);
4464   free(outputCtx->neighborlist);
4465   PetscFunctionReturn(0);
4466 }
4467 
4468 #undef __FUNCT__
4469 #define __FUNCT__ "DMPlexGenerate_Triangle"
4470 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4471 {
4472   MPI_Comm             comm;
4473   PetscInt             dim              = 2;
4474   const PetscBool      createConvexHull = PETSC_FALSE;
4475   const PetscBool      constrained      = PETSC_FALSE;
4476   struct triangulateio in;
4477   struct triangulateio out;
4478   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4479   PetscMPIInt          rank;
4480   PetscErrorCode       ierr;
4481 
4482   PetscFunctionBegin;
4483   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4484   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4485   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4486   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4487   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4488 
4489   in.numberofpoints = vEnd - vStart;
4490   if (in.numberofpoints > 0) {
4491     PetscSection coordSection;
4492     Vec          coordinates;
4493     PetscScalar *array;
4494 
4495     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4496     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4497     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4498     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4499     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4500     for (v = vStart; v < vEnd; ++v) {
4501       const PetscInt idx = v - vStart;
4502       PetscInt       off, d;
4503 
4504       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4505       for (d = 0; d < dim; ++d) {
4506         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4507       }
4508       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4509     }
4510     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4511   }
4512   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4513   in.numberofsegments = eEnd - eStart;
4514   if (in.numberofsegments > 0) {
4515     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4516     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4517     for (e = eStart; e < eEnd; ++e) {
4518       const PetscInt  idx = e - eStart;
4519       const PetscInt *cone;
4520 
4521       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4522 
4523       in.segmentlist[idx*2+0] = cone[0] - vStart;
4524       in.segmentlist[idx*2+1] = cone[1] - vStart;
4525 
4526       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4527     }
4528   }
4529 #if 0 /* Do not currently support holes */
4530   PetscReal *holeCoords;
4531   PetscInt   h, d;
4532 
4533   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4534   if (in.numberofholes > 0) {
4535     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4536     for (h = 0; h < in.numberofholes; ++h) {
4537       for (d = 0; d < dim; ++d) {
4538         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4539       }
4540     }
4541   }
4542 #endif
4543   if (!rank) {
4544     char args[32];
4545 
4546     /* Take away 'Q' for verbose output */
4547     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4548     if (createConvexHull) {
4549       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4550     }
4551     if (constrained) {
4552       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4553     }
4554     triangulate(args, &in, &out, NULL);
4555   }
4556   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4557   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4558   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4559   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4560   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4561 
4562   {
4563     const PetscInt numCorners  = 3;
4564     const PetscInt numCells    = out.numberoftriangles;
4565     const PetscInt numVertices = out.numberofpoints;
4566     const int     *cells      = out.trianglelist;
4567     const double  *meshCoords = out.pointlist;
4568 
4569     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4570     /* Set labels */
4571     for (v = 0; v < numVertices; ++v) {
4572       if (out.pointmarkerlist[v]) {
4573         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4574       }
4575     }
4576     if (interpolate) {
4577       for (e = 0; e < out.numberofedges; e++) {
4578         if (out.edgemarkerlist[e]) {
4579           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4580           const PetscInt *edges;
4581           PetscInt        numEdges;
4582 
4583           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4584           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4585           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4586           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4587         }
4588       }
4589     }
4590     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4591   }
4592 #if 0 /* Do not currently support holes */
4593   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4594 #endif
4595   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4596   PetscFunctionReturn(0);
4597 }
4598 
4599 #undef __FUNCT__
4600 #define __FUNCT__ "DMPlexRefine_Triangle"
4601 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4602 {
4603   MPI_Comm             comm;
4604   PetscInt             dim  = 2;
4605   struct triangulateio in;
4606   struct triangulateio out;
4607   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4608   PetscMPIInt          rank;
4609   PetscErrorCode       ierr;
4610 
4611   PetscFunctionBegin;
4612   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4613   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4614   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4615   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4616   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4617   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4618   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4619 
4620   in.numberofpoints = vEnd - vStart;
4621   if (in.numberofpoints > 0) {
4622     PetscSection coordSection;
4623     Vec          coordinates;
4624     PetscScalar *array;
4625 
4626     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4627     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4628     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4629     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4630     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4631     for (v = vStart; v < vEnd; ++v) {
4632       const PetscInt idx = v - vStart;
4633       PetscInt       off, d;
4634 
4635       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4636       for (d = 0; d < dim; ++d) {
4637         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4638       }
4639       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4640     }
4641     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4642   }
4643   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4644 
4645   in.numberofcorners   = 3;
4646   in.numberoftriangles = cEnd - cStart;
4647 
4648   in.trianglearealist  = (double*) maxVolumes;
4649   if (in.numberoftriangles > 0) {
4650     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4651     for (c = cStart; c < cEnd; ++c) {
4652       const PetscInt idx      = c - cStart;
4653       PetscInt      *closure = NULL;
4654       PetscInt       closureSize;
4655 
4656       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4657       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4658       for (v = 0; v < 3; ++v) {
4659         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4660       }
4661       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4662     }
4663   }
4664   /* TODO: Segment markers are missing on input */
4665 #if 0 /* Do not currently support holes */
4666   PetscReal *holeCoords;
4667   PetscInt   h, d;
4668 
4669   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4670   if (in.numberofholes > 0) {
4671     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4672     for (h = 0; h < in.numberofholes; ++h) {
4673       for (d = 0; d < dim; ++d) {
4674         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4675       }
4676     }
4677   }
4678 #endif
4679   if (!rank) {
4680     char args[32];
4681 
4682     /* Take away 'Q' for verbose output */
4683     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4684     triangulate(args, &in, &out, NULL);
4685   }
4686   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4687   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4688   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4689   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4690   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4691 
4692   {
4693     const PetscInt numCorners  = 3;
4694     const PetscInt numCells    = out.numberoftriangles;
4695     const PetscInt numVertices = out.numberofpoints;
4696     const int     *cells      = out.trianglelist;
4697     const double  *meshCoords = out.pointlist;
4698     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4699 
4700     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4701     /* Set labels */
4702     for (v = 0; v < numVertices; ++v) {
4703       if (out.pointmarkerlist[v]) {
4704         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4705       }
4706     }
4707     if (interpolate) {
4708       PetscInt e;
4709 
4710       for (e = 0; e < out.numberofedges; e++) {
4711         if (out.edgemarkerlist[e]) {
4712           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4713           const PetscInt *edges;
4714           PetscInt        numEdges;
4715 
4716           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4717           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4718           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4719           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4720         }
4721       }
4722     }
4723     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4724   }
4725 #if 0 /* Do not currently support holes */
4726   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4727 #endif
4728   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4729   PetscFunctionReturn(0);
4730 }
4731 #endif
4732 
4733 #if defined(PETSC_HAVE_TETGEN)
4734 #include <tetgen.h>
4735 #undef __FUNCT__
4736 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4737 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4738 {
4739   MPI_Comm       comm;
4740   const PetscInt dim  = 3;
4741   ::tetgenio     in;
4742   ::tetgenio     out;
4743   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4744   PetscMPIInt    rank;
4745   PetscErrorCode ierr;
4746 
4747   PetscFunctionBegin;
4748   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4749   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4750   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4751   in.numberofpoints = vEnd - vStart;
4752   if (in.numberofpoints > 0) {
4753     PetscSection coordSection;
4754     Vec          coordinates;
4755     PetscScalar *array;
4756 
4757     in.pointlist       = new double[in.numberofpoints*dim];
4758     in.pointmarkerlist = new int[in.numberofpoints];
4759 
4760     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4761     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4762     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4763     for (v = vStart; v < vEnd; ++v) {
4764       const PetscInt idx = v - vStart;
4765       PetscInt       off, d;
4766 
4767       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4768       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
4769       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4770     }
4771     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4772   }
4773   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4774 
4775   in.numberoffacets = fEnd - fStart;
4776   if (in.numberoffacets > 0) {
4777     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4778     in.facetmarkerlist = new int[in.numberoffacets];
4779     for (f = fStart; f < fEnd; ++f) {
4780       const PetscInt idx     = f - fStart;
4781       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
4782 
4783       in.facetlist[idx].numberofpolygons = 1;
4784       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4785       in.facetlist[idx].numberofholes    = 0;
4786       in.facetlist[idx].holelist         = NULL;
4787 
4788       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4789       for (p = 0; p < numPoints*2; p += 2) {
4790         const PetscInt point = points[p];
4791         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4792       }
4793 
4794       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4795       poly->numberofvertices = numVertices;
4796       poly->vertexlist       = new int[poly->numberofvertices];
4797       for (v = 0; v < numVertices; ++v) {
4798         const PetscInt vIdx = points[v] - vStart;
4799         poly->vertexlist[v] = vIdx;
4800       }
4801       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4802       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4803     }
4804   }
4805   if (!rank) {
4806     char args[32];
4807 
4808     /* Take away 'Q' for verbose output */
4809     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4810     ::tetrahedralize(args, &in, &out);
4811   }
4812   {
4813     const PetscInt numCorners  = 4;
4814     const PetscInt numCells    = out.numberoftetrahedra;
4815     const PetscInt numVertices = out.numberofpoints;
4816     const int     *cells      = out.tetrahedronlist;
4817     const double  *meshCoords = out.pointlist;
4818 
4819     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4820     /* Set labels */
4821     for (v = 0; v < numVertices; ++v) {
4822       if (out.pointmarkerlist[v]) {
4823         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4824       }
4825     }
4826     if (interpolate) {
4827       PetscInt e;
4828 
4829       for (e = 0; e < out.numberofedges; e++) {
4830         if (out.edgemarkerlist[e]) {
4831           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4832           const PetscInt *edges;
4833           PetscInt        numEdges;
4834 
4835           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4836           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4837           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4838           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4839         }
4840       }
4841       for (f = 0; f < out.numberoftrifaces; f++) {
4842         if (out.trifacemarkerlist[f]) {
4843           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4844           const PetscInt *faces;
4845           PetscInt        numFaces;
4846 
4847           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4848           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4849           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4850           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4851         }
4852       }
4853     }
4854     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4855   }
4856   PetscFunctionReturn(0);
4857 }
4858 
4859 #undef __FUNCT__
4860 #define __FUNCT__ "DMPlexRefine_Tetgen"
4861 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4862 {
4863   MPI_Comm       comm;
4864   const PetscInt dim  = 3;
4865   ::tetgenio     in;
4866   ::tetgenio     out;
4867   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4868   PetscMPIInt    rank;
4869   PetscErrorCode ierr;
4870 
4871   PetscFunctionBegin;
4872   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4873   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4874   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4875   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4876   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4877 
4878   in.numberofpoints = vEnd - vStart;
4879   if (in.numberofpoints > 0) {
4880     PetscSection coordSection;
4881     Vec          coordinates;
4882     PetscScalar *array;
4883 
4884     in.pointlist       = new double[in.numberofpoints*dim];
4885     in.pointmarkerlist = new int[in.numberofpoints];
4886 
4887     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4888     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4889     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4890     for (v = vStart; v < vEnd; ++v) {
4891       const PetscInt idx = v - vStart;
4892       PetscInt       off, d;
4893 
4894       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4895       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
4896       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4897     }
4898     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4899   }
4900   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4901 
4902   in.numberofcorners       = 4;
4903   in.numberoftetrahedra    = cEnd - cStart;
4904   in.tetrahedronvolumelist = (double*) maxVolumes;
4905   if (in.numberoftetrahedra > 0) {
4906     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
4907     for (c = cStart; c < cEnd; ++c) {
4908       const PetscInt idx      = c - cStart;
4909       PetscInt      *closure = NULL;
4910       PetscInt       closureSize;
4911 
4912       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4913       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4914       for (v = 0; v < 4; ++v) {
4915         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4916       }
4917       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4918     }
4919   }
4920   /* TODO: Put in boundary faces with markers */
4921   if (!rank) {
4922     char args[32];
4923 
4924     /* Take away 'Q' for verbose output */
4925     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
4926     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
4927     ::tetrahedralize(args, &in, &out);
4928   }
4929   in.tetrahedronvolumelist = NULL;
4930 
4931   {
4932     const PetscInt numCorners  = 4;
4933     const PetscInt numCells    = out.numberoftetrahedra;
4934     const PetscInt numVertices = out.numberofpoints;
4935     const int     *cells      = out.tetrahedronlist;
4936     const double  *meshCoords = out.pointlist;
4937     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4938 
4939     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4940     /* Set labels */
4941     for (v = 0; v < numVertices; ++v) {
4942       if (out.pointmarkerlist[v]) {
4943         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4944       }
4945     }
4946     if (interpolate) {
4947       PetscInt e, f;
4948 
4949       for (e = 0; e < out.numberofedges; e++) {
4950         if (out.edgemarkerlist[e]) {
4951           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4952           const PetscInt *edges;
4953           PetscInt        numEdges;
4954 
4955           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4956           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4957           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4958           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4959         }
4960       }
4961       for (f = 0; f < out.numberoftrifaces; f++) {
4962         if (out.trifacemarkerlist[f]) {
4963           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4964           const PetscInt *faces;
4965           PetscInt        numFaces;
4966 
4967           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4968           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4969           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4970           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4971         }
4972       }
4973     }
4974     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4975   }
4976   PetscFunctionReturn(0);
4977 }
4978 #endif
4979 
4980 #if defined(PETSC_HAVE_CTETGEN)
4981 #include "ctetgen.h"
4982 
4983 #undef __FUNCT__
4984 #define __FUNCT__ "DMPlexGenerate_CTetgen"
4985 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4986 {
4987   MPI_Comm       comm;
4988   const PetscInt dim  = 3;
4989   PLC           *in, *out;
4990   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4991   PetscMPIInt    rank;
4992   PetscErrorCode ierr;
4993 
4994   PetscFunctionBegin;
4995   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4996   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
4997   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4998   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4999   ierr = PLCCreate(&in);CHKERRQ(ierr);
5000   ierr = PLCCreate(&out);CHKERRQ(ierr);
5001 
5002   in->numberofpoints = vEnd - vStart;
5003   if (in->numberofpoints > 0) {
5004     PetscSection coordSection;
5005     Vec          coordinates;
5006     PetscScalar *array;
5007 
5008     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5009     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5010     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5011     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5012     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5013     for (v = vStart; v < vEnd; ++v) {
5014       const PetscInt idx = v - vStart;
5015       PetscInt       off, d, m;
5016 
5017       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5018       for (d = 0; d < dim; ++d) {
5019         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5020       }
5021       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5022 
5023       in->pointmarkerlist[idx] = (int) m;
5024     }
5025     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5026   }
5027   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5028 
5029   in->numberoffacets = fEnd - fStart;
5030   if (in->numberoffacets > 0) {
5031     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5032     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5033     for (f = fStart; f < fEnd; ++f) {
5034       const PetscInt idx     = f - fStart;
5035       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5036       polygon       *poly;
5037 
5038       in->facetlist[idx].numberofpolygons = 1;
5039 
5040       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5041 
5042       in->facetlist[idx].numberofholes    = 0;
5043       in->facetlist[idx].holelist         = NULL;
5044 
5045       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5046       for (p = 0; p < numPoints*2; p += 2) {
5047         const PetscInt point = points[p];
5048         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5049       }
5050 
5051       poly                   = in->facetlist[idx].polygonlist;
5052       poly->numberofvertices = numVertices;
5053       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5054       for (v = 0; v < numVertices; ++v) {
5055         const PetscInt vIdx = points[v] - vStart;
5056         poly->vertexlist[v] = vIdx;
5057       }
5058       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5059       in->facetmarkerlist[idx] = (int) m;
5060       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5061     }
5062   }
5063   if (!rank) {
5064     TetGenOpts t;
5065 
5066     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5067     t.in        = boundary; /* Should go away */
5068     t.plc       = 1;
5069     t.quality   = 1;
5070     t.edgesout  = 1;
5071     t.zeroindex = 1;
5072     t.quiet     = 1;
5073     t.verbose   = verbose;
5074     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5075     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5076   }
5077   {
5078     const PetscInt numCorners  = 4;
5079     const PetscInt numCells    = out->numberoftetrahedra;
5080     const PetscInt numVertices = out->numberofpoints;
5081     const int     *cells      = out->tetrahedronlist;
5082     const double  *meshCoords = out->pointlist;
5083 
5084     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
5085     /* Set labels */
5086     for (v = 0; v < numVertices; ++v) {
5087       if (out->pointmarkerlist[v]) {
5088         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5089       }
5090     }
5091     if (interpolate) {
5092       PetscInt e;
5093 
5094       for (e = 0; e < out->numberofedges; e++) {
5095         if (out->edgemarkerlist[e]) {
5096           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5097           const PetscInt *edges;
5098           PetscInt        numEdges;
5099 
5100           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5101           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5102           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5103           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5104         }
5105       }
5106       for (f = 0; f < out->numberoftrifaces; f++) {
5107         if (out->trifacemarkerlist[f]) {
5108           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5109           const PetscInt *faces;
5110           PetscInt        numFaces;
5111 
5112           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5113           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5114           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5115           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5116         }
5117       }
5118     }
5119     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5120   }
5121 
5122   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5123   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5124   PetscFunctionReturn(0);
5125 }
5126 
5127 #undef __FUNCT__
5128 #define __FUNCT__ "DMPlexRefine_CTetgen"
5129 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5130 {
5131   MPI_Comm       comm;
5132   const PetscInt dim  = 3;
5133   PLC           *in, *out;
5134   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5135   PetscMPIInt    rank;
5136   PetscErrorCode ierr;
5137 
5138   PetscFunctionBegin;
5139   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5140   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5141   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5142   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5143   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5144   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5145   ierr = PLCCreate(&in);CHKERRQ(ierr);
5146   ierr = PLCCreate(&out);CHKERRQ(ierr);
5147 
5148   in->numberofpoints = vEnd - vStart;
5149   if (in->numberofpoints > 0) {
5150     PetscSection coordSection;
5151     Vec          coordinates;
5152     PetscScalar *array;
5153 
5154     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5155     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5156     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5157     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5158     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5159     for (v = vStart; v < vEnd; ++v) {
5160       const PetscInt idx = v - vStart;
5161       PetscInt       off, d, m;
5162 
5163       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5164       for (d = 0; d < dim; ++d) {
5165         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5166       }
5167       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5168 
5169       in->pointmarkerlist[idx] = (int) m;
5170     }
5171     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5172   }
5173   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5174 
5175   in->numberofcorners       = 4;
5176   in->numberoftetrahedra    = cEnd - cStart;
5177   in->tetrahedronvolumelist = maxVolumes;
5178   if (in->numberoftetrahedra > 0) {
5179     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5180     for (c = cStart; c < cEnd; ++c) {
5181       const PetscInt idx      = c - cStart;
5182       PetscInt      *closure = NULL;
5183       PetscInt       closureSize;
5184 
5185       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5186       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5187       for (v = 0; v < 4; ++v) {
5188         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5189       }
5190       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5191     }
5192   }
5193   if (!rank) {
5194     TetGenOpts t;
5195 
5196     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5197 
5198     t.in        = dm; /* Should go away */
5199     t.refine    = 1;
5200     t.varvolume = 1;
5201     t.quality   = 1;
5202     t.edgesout  = 1;
5203     t.zeroindex = 1;
5204     t.quiet     = 1;
5205     t.verbose   = verbose; /* Change this */
5206 
5207     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5208     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5209   }
5210   {
5211     const PetscInt numCorners  = 4;
5212     const PetscInt numCells    = out->numberoftetrahedra;
5213     const PetscInt numVertices = out->numberofpoints;
5214     const int     *cells       = out->tetrahedronlist;
5215     const double  *meshCoords  = out->pointlist;
5216     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5217 
5218     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
5219     /* Set labels */
5220     for (v = 0; v < numVertices; ++v) {
5221       if (out->pointmarkerlist[v]) {
5222         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5223       }
5224     }
5225     if (interpolate) {
5226       PetscInt e, f;
5227 
5228       for (e = 0; e < out->numberofedges; e++) {
5229         if (out->edgemarkerlist[e]) {
5230           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5231           const PetscInt *edges;
5232           PetscInt        numEdges;
5233 
5234           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5235           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5236           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5237           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5238         }
5239       }
5240       for (f = 0; f < out->numberoftrifaces; f++) {
5241         if (out->trifacemarkerlist[f]) {
5242           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5243           const PetscInt *faces;
5244           PetscInt        numFaces;
5245 
5246           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5247           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5248           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5249           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5250         }
5251       }
5252     }
5253     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5254   }
5255   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5256   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5257   PetscFunctionReturn(0);
5258 }
5259 #endif
5260 
5261 #undef __FUNCT__
5262 #define __FUNCT__ "DMPlexGenerate"
5263 /*@C
5264   DMPlexGenerate - Generates a mesh.
5265 
5266   Not Collective
5267 
5268   Input Parameters:
5269 + boundary - The DMPlex boundary object
5270 . name - The mesh generation package name
5271 - interpolate - Flag to create intermediate mesh elements
5272 
5273   Output Parameter:
5274 . mesh - The DMPlex object
5275 
5276   Level: intermediate
5277 
5278 .keywords: mesh, elements
5279 .seealso: DMPlexCreate(), DMRefine()
5280 @*/
5281 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5282 {
5283   PetscInt       dim;
5284   char           genname[1024];
5285   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5286   PetscErrorCode ierr;
5287 
5288   PetscFunctionBegin;
5289   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5290   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5291   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5292   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5293   if (flg) name = genname;
5294   if (name) {
5295     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5296     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5297     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5298   }
5299   switch (dim) {
5300   case 1:
5301     if (!name || isTriangle) {
5302 #if defined(PETSC_HAVE_TRIANGLE)
5303       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5304 #else
5305       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5306 #endif
5307     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5308     break;
5309   case 2:
5310     if (!name || isCTetgen) {
5311 #if defined(PETSC_HAVE_CTETGEN)
5312       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5313 #else
5314       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5315 #endif
5316     } else if (isTetgen) {
5317 #if defined(PETSC_HAVE_TETGEN)
5318       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5319 #else
5320       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5321 #endif
5322     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5323     break;
5324   default:
5325     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5326   }
5327   PetscFunctionReturn(0);
5328 }
5329 
5330 typedef PetscInt CellRefiner;
5331 
5332 #undef __FUNCT__
5333 #define __FUNCT__ "GetDepthStart_Private"
5334 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5335 {
5336   PetscFunctionBegin;
5337   if (cStart) *cStart = 0;
5338   if (vStart) *vStart = depthSize[depth];
5339   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5340   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5341   PetscFunctionReturn(0);
5342 }
5343 
5344 #undef __FUNCT__
5345 #define __FUNCT__ "GetDepthEnd_Private"
5346 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5347 {
5348   PetscFunctionBegin;
5349   if (cEnd) *cEnd = depthSize[depth];
5350   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5351   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5352   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5353   PetscFunctionReturn(0);
5354 }
5355 
5356 #undef __FUNCT__
5357 #define __FUNCT__ "CellRefinerGetSizes"
5358 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5359 {
5360   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5361   PetscErrorCode ierr;
5362 
5363   PetscFunctionBegin;
5364   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5365   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5366   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5367   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5368   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5369   switch (refiner) {
5370   case 1:
5371     /* Simplicial 2D */
5372     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5373     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5374     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5375     break;
5376   case 3:
5377     /* Hybrid 2D */
5378     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5379     cMax = PetscMin(cEnd, cMax);
5380     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5381     fMax         = PetscMin(fEnd, fMax);
5382     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5383     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 */
5384     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5385     break;
5386   case 2:
5387     /* Hex 2D */
5388     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5389     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5390     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5391     break;
5392   default:
5393     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5394   }
5395   PetscFunctionReturn(0);
5396 }
5397 
5398 #undef __FUNCT__
5399 #define __FUNCT__ "CellRefinerSetConeSizes"
5400 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5401 {
5402   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5403   PetscErrorCode ierr;
5404 
5405   PetscFunctionBegin;
5406   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
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   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5412   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5413   switch (refiner) {
5414   case 1:
5415     /* Simplicial 2D */
5416     /* All cells have 3 faces */
5417     for (c = cStart; c < cEnd; ++c) {
5418       for (r = 0; r < 4; ++r) {
5419         const PetscInt newp = (c - cStart)*4 + r;
5420 
5421         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5422       }
5423     }
5424     /* Split faces have 2 vertices and the same cells as the parent */
5425     for (f = fStart; f < fEnd; ++f) {
5426       for (r = 0; r < 2; ++r) {
5427         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5428         PetscInt       size;
5429 
5430         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5431         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5432         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5433       }
5434     }
5435     /* Interior faces have 2 vertices and 2 cells */
5436     for (c = cStart; c < cEnd; ++c) {
5437       for (r = 0; r < 3; ++r) {
5438         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5439 
5440         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5441         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5442       }
5443     }
5444     /* Old vertices have identical supports */
5445     for (v = vStart; v < vEnd; ++v) {
5446       const PetscInt newp = vStartNew + (v - vStart);
5447       PetscInt       size;
5448 
5449       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5450       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5451     }
5452     /* Face vertices have 2 + cells*2 supports */
5453     for (f = fStart; f < fEnd; ++f) {
5454       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5455       PetscInt       size;
5456 
5457       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5458       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5459     }
5460     break;
5461   case 2:
5462     /* Hex 2D */
5463     /* All cells have 4 faces */
5464     for (c = cStart; c < cEnd; ++c) {
5465       for (r = 0; r < 4; ++r) {
5466         const PetscInt newp = (c - cStart)*4 + r;
5467 
5468         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5469       }
5470     }
5471     /* Split faces have 2 vertices and the same cells as the parent */
5472     for (f = fStart; f < fEnd; ++f) {
5473       for (r = 0; r < 2; ++r) {
5474         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5475         PetscInt       size;
5476 
5477         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5478         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5479         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5480       }
5481     }
5482     /* Interior faces have 2 vertices and 2 cells */
5483     for (c = cStart; c < cEnd; ++c) {
5484       for (r = 0; r < 4; ++r) {
5485         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5486 
5487         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5488         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5489       }
5490     }
5491     /* Old vertices have identical supports */
5492     for (v = vStart; v < vEnd; ++v) {
5493       const PetscInt newp = vStartNew + (v - vStart);
5494       PetscInt       size;
5495 
5496       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5497       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5498     }
5499     /* Face vertices have 2 + cells supports */
5500     for (f = fStart; f < fEnd; ++f) {
5501       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5502       PetscInt       size;
5503 
5504       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5505       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5506     }
5507     /* Cell vertices have 4 supports */
5508     for (c = cStart; c < cEnd; ++c) {
5509       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5510 
5511       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5512     }
5513     break;
5514   case 3:
5515     /* Hybrid 2D */
5516     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5517     cMax = PetscMin(cEnd, cMax);
5518     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5519     fMax = PetscMin(fEnd, fMax);
5520     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5521     /* Interior cells have 3 faces */
5522     for (c = cStart; c < cMax; ++c) {
5523       for (r = 0; r < 4; ++r) {
5524         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5525 
5526         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5527       }
5528     }
5529     /* Hybrid cells have 4 faces */
5530     for (c = cMax; c < cEnd; ++c) {
5531       for (r = 0; r < 2; ++r) {
5532         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5533 
5534         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5535       }
5536     }
5537     /* Interior split faces have 2 vertices and the same cells as the parent */
5538     for (f = fStart; f < fMax; ++f) {
5539       for (r = 0; r < 2; ++r) {
5540         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5541         PetscInt       size;
5542 
5543         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5544         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5545         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5546       }
5547     }
5548     /* Interior cell faces have 2 vertices and 2 cells */
5549     for (c = cStart; c < cMax; ++c) {
5550       for (r = 0; r < 3; ++r) {
5551         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5552 
5553         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5554         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5555       }
5556     }
5557     /* Hybrid faces have 2 vertices and the same cells */
5558     for (f = fMax; f < fEnd; ++f) {
5559       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5560       PetscInt       size;
5561 
5562       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5563       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5564       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5565     }
5566     /* Hybrid cell faces have 2 vertices and 2 cells */
5567     for (c = cMax; c < cEnd; ++c) {
5568       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5569 
5570       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5571       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5572     }
5573     /* Old vertices have identical supports */
5574     for (v = vStart; v < vEnd; ++v) {
5575       const PetscInt newp = vStartNew + (v - vStart);
5576       PetscInt       size;
5577 
5578       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5579       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5580     }
5581     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5582     for (f = fStart; f < fMax; ++f) {
5583       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5584       const PetscInt *support;
5585       PetscInt       size, newSize = 2, s;
5586 
5587       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5588       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5589       for (s = 0; s < size; ++s) {
5590         if (support[s] >= cMax) newSize += 1;
5591         else newSize += 2;
5592       }
5593       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5594     }
5595     break;
5596   default:
5597     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5598   }
5599   PetscFunctionReturn(0);
5600 }
5601 
5602 #undef __FUNCT__
5603 #define __FUNCT__ "CellRefinerSetCones"
5604 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5605 {
5606   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;
5607   PetscInt       maxSupportSize, *supportRef;
5608   PetscErrorCode ierr;
5609 
5610   PetscFunctionBegin;
5611   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5612   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5613   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5614   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5615   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5616   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5617   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5618   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5619   switch (refiner) {
5620   case 1:
5621     /* Simplicial 2D */
5622     /*
5623      2
5624      |\
5625      | \
5626      |  \
5627      |   \
5628      | C  \
5629      |     \
5630      |      \
5631      2---1---1
5632      |\  D  / \
5633      | 2   0   \
5634      |A \ /  B  \
5635      0---0-------1
5636      */
5637     /* All cells have 3 faces */
5638     for (c = cStart; c < cEnd; ++c) {
5639       const PetscInt  newp = cStartNew + (c - cStart)*4;
5640       const PetscInt *cone, *ornt;
5641       PetscInt        coneNew[3], orntNew[3];
5642 
5643       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5644       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5645       /* A triangle */
5646       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5647       orntNew[0] = ornt[0];
5648       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5649       orntNew[1] = -2;
5650       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5651       orntNew[2] = ornt[2];
5652       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5653       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5654 #if 1
5655       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);
5656       for (p = 0; p < 3; ++p) {
5657         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);
5658       }
5659 #endif
5660       /* B triangle */
5661       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5662       orntNew[0] = ornt[0];
5663       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5664       orntNew[1] = ornt[1];
5665       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5666       orntNew[2] = -2;
5667       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5668       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5669 #if 1
5670       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);
5671       for (p = 0; p < 3; ++p) {
5672         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);
5673       }
5674 #endif
5675       /* C triangle */
5676       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5677       orntNew[0] = -2;
5678       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5679       orntNew[1] = ornt[1];
5680       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5681       orntNew[2] = ornt[2];
5682       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5683       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5684 #if 1
5685       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);
5686       for (p = 0; p < 3; ++p) {
5687         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);
5688       }
5689 #endif
5690       /* D triangle */
5691       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5692       orntNew[0] = 0;
5693       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5694       orntNew[1] = 0;
5695       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5696       orntNew[2] = 0;
5697       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5698       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5699 #if 1
5700       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);
5701       for (p = 0; p < 3; ++p) {
5702         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);
5703       }
5704 #endif
5705     }
5706     /* Split faces have 2 vertices and the same cells as the parent */
5707     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5708     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5709     for (f = fStart; f < fEnd; ++f) {
5710       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5711 
5712       for (r = 0; r < 2; ++r) {
5713         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5714         const PetscInt *cone, *support;
5715         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5716 
5717         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5718         coneNew[0]       = vStartNew + (cone[0] - vStart);
5719         coneNew[1]       = vStartNew + (cone[1] - vStart);
5720         coneNew[(r+1)%2] = newv;
5721         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5722 #if 1
5723         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5724         for (p = 0; p < 2; ++p) {
5725           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);
5726         }
5727 #endif
5728         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5729         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5730         for (s = 0; s < supportSize; ++s) {
5731           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5732           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5733           for (c = 0; c < coneSize; ++c) {
5734             if (cone[c] == f) break;
5735           }
5736           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5737         }
5738         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5739 #if 1
5740         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5741         for (p = 0; p < supportSize; ++p) {
5742           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);
5743         }
5744 #endif
5745       }
5746     }
5747     /* Interior faces have 2 vertices and 2 cells */
5748     for (c = cStart; c < cEnd; ++c) {
5749       const PetscInt *cone;
5750 
5751       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5752       for (r = 0; r < 3; ++r) {
5753         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5754         PetscInt       coneNew[2];
5755         PetscInt       supportNew[2];
5756 
5757         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5758         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5759         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5760 #if 1
5761         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5762         for (p = 0; p < 2; ++p) {
5763           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);
5764         }
5765 #endif
5766         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5767         supportNew[1] = (c - cStart)*4 + 3;
5768         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5769 #if 1
5770         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5771         for (p = 0; p < 2; ++p) {
5772           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);
5773         }
5774 #endif
5775       }
5776     }
5777     /* Old vertices have identical supports */
5778     for (v = vStart; v < vEnd; ++v) {
5779       const PetscInt  newp = vStartNew + (v - vStart);
5780       const PetscInt *support, *cone;
5781       PetscInt        size, s;
5782 
5783       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5784       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5785       for (s = 0; s < size; ++s) {
5786         PetscInt r = 0;
5787 
5788         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5789         if (cone[1] == v) r = 1;
5790         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5791       }
5792       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5793 #if 1
5794       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5795       for (p = 0; p < size; ++p) {
5796         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);
5797       }
5798 #endif
5799     }
5800     /* Face vertices have 2 + cells*2 supports */
5801     for (f = fStart; f < fEnd; ++f) {
5802       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5803       const PetscInt *cone, *support;
5804       PetscInt        size, s;
5805 
5806       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5807       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5808       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5809       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5810       for (s = 0; s < size; ++s) {
5811         PetscInt r = 0;
5812 
5813         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5814         if      (cone[1] == f) r = 1;
5815         else if (cone[2] == f) r = 2;
5816         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5817         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5818       }
5819       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5820 #if 1
5821       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5822       for (p = 0; p < 2+size*2; ++p) {
5823         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);
5824       }
5825 #endif
5826     }
5827     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5828     break;
5829   case 2:
5830     /* Hex 2D */
5831     /*
5832      3---------2---------2
5833      |         |         |
5834      |    D    2    C    |
5835      |         |         |
5836      3----3----0----1----1
5837      |         |         |
5838      |    A    0    B    |
5839      |         |         |
5840      0---------0---------1
5841      */
5842     /* All cells have 4 faces */
5843     for (c = cStart; c < cEnd; ++c) {
5844       const PetscInt  newp = (c - cStart)*4;
5845       const PetscInt *cone, *ornt;
5846       PetscInt        coneNew[4], orntNew[4];
5847 
5848       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5849       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5850       /* A quad */
5851       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5852       orntNew[0] = ornt[0];
5853       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5854       orntNew[1] = 0;
5855       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5856       orntNew[2] = -2;
5857       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5858       orntNew[3] = ornt[3];
5859       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5860       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5861 #if 1
5862       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);
5863       for (p = 0; p < 4; ++p) {
5864         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);
5865       }
5866 #endif
5867       /* B quad */
5868       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5869       orntNew[0] = ornt[0];
5870       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5871       orntNew[1] = ornt[1];
5872       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5873       orntNew[2] = 0;
5874       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5875       orntNew[3] = -2;
5876       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5877       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5878 #if 1
5879       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);
5880       for (p = 0; p < 4; ++p) {
5881         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);
5882       }
5883 #endif
5884       /* C quad */
5885       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5886       orntNew[0] = -2;
5887       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5888       orntNew[1] = ornt[1];
5889       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5890       orntNew[2] = ornt[2];
5891       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5892       orntNew[3] = 0;
5893       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5894       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5895 #if 1
5896       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);
5897       for (p = 0; p < 4; ++p) {
5898         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);
5899       }
5900 #endif
5901       /* D quad */
5902       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5903       orntNew[0] = 0;
5904       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5905       orntNew[1] = -2;
5906       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5907       orntNew[2] = ornt[2];
5908       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
5909       orntNew[3] = ornt[3];
5910       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5911       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5912 #if 1
5913       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);
5914       for (p = 0; p < 4; ++p) {
5915         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);
5916       }
5917 #endif
5918     }
5919     /* Split faces have 2 vertices and the same cells as the parent */
5920     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5921     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5922     for (f = fStart; f < fEnd; ++f) {
5923       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5924 
5925       for (r = 0; r < 2; ++r) {
5926         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5927         const PetscInt *cone, *support;
5928         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5929 
5930         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5931         coneNew[0]       = vStartNew + (cone[0] - vStart);
5932         coneNew[1]       = vStartNew + (cone[1] - vStart);
5933         coneNew[(r+1)%2] = newv;
5934         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5935 #if 1
5936         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5937         for (p = 0; p < 2; ++p) {
5938           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);
5939         }
5940 #endif
5941         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5942         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5943         for (s = 0; s < supportSize; ++s) {
5944           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5945           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5946           for (c = 0; c < coneSize; ++c) {
5947             if (cone[c] == f) break;
5948           }
5949           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
5950         }
5951         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5952 #if 1
5953         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5954         for (p = 0; p < supportSize; ++p) {
5955           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);
5956         }
5957 #endif
5958       }
5959     }
5960     /* Interior faces have 2 vertices and 2 cells */
5961     for (c = cStart; c < cEnd; ++c) {
5962       const PetscInt *cone;
5963       PetscInt        coneNew[2], supportNew[2];
5964 
5965       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5966       for (r = 0; r < 4; ++r) {
5967         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5968 
5969         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
5970         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
5971         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5972 #if 1
5973         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5974         for (p = 0; p < 2; ++p) {
5975           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);
5976         }
5977 #endif
5978         supportNew[0] = (c - cStart)*4 + r;
5979         supportNew[1] = (c - cStart)*4 + (r+1)%4;
5980         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5981 #if 1
5982         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5983         for (p = 0; p < 2; ++p) {
5984           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);
5985         }
5986 #endif
5987       }
5988     }
5989     /* Old vertices have identical supports */
5990     for (v = vStart; v < vEnd; ++v) {
5991       const PetscInt  newp = vStartNew + (v - vStart);
5992       const PetscInt *support, *cone;
5993       PetscInt        size, s;
5994 
5995       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5996       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5997       for (s = 0; s < size; ++s) {
5998         PetscInt r = 0;
5999 
6000         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6001         if (cone[1] == v) r = 1;
6002         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6003       }
6004       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6005 #if 1
6006       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6007       for (p = 0; p < size; ++p) {
6008         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);
6009       }
6010 #endif
6011     }
6012     /* Face vertices have 2 + cells supports */
6013     for (f = fStart; f < fEnd; ++f) {
6014       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6015       const PetscInt *cone, *support;
6016       PetscInt        size, s;
6017 
6018       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6019       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6020       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6021       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6022       for (s = 0; s < size; ++s) {
6023         PetscInt r = 0;
6024 
6025         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6026         if      (cone[1] == f) r = 1;
6027         else if (cone[2] == f) r = 2;
6028         else if (cone[3] == f) r = 3;
6029         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6030       }
6031       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6032 #if 1
6033       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6034       for (p = 0; p < 2+size; ++p) {
6035         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);
6036       }
6037 #endif
6038     }
6039     /* Cell vertices have 4 supports */
6040     for (c = cStart; c < cEnd; ++c) {
6041       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6042       PetscInt       supportNew[4];
6043 
6044       for (r = 0; r < 4; ++r) {
6045         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6046       }
6047       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6048     }
6049     break;
6050   case 3:
6051     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6052     cMax = PetscMin(cEnd, cMax);
6053     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6054     fMax = PetscMin(fEnd, fMax);
6055     /* Interior cells have 3 faces */
6056     for (c = cStart; c < cMax; ++c) {
6057       const PetscInt  newp = cStartNew + (c - cStart)*4;
6058       const PetscInt *cone, *ornt;
6059       PetscInt        coneNew[3], orntNew[3];
6060 
6061       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6062       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6063       /* A triangle */
6064       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6065       orntNew[0] = ornt[0];
6066       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6067       orntNew[1] = -2;
6068       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6069       orntNew[2] = ornt[2];
6070       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6071       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6072 #if 1
6073       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);
6074       for (p = 0; p < 3; ++p) {
6075         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);
6076       }
6077 #endif
6078       /* B triangle */
6079       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6080       orntNew[0] = ornt[0];
6081       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6082       orntNew[1] = ornt[1];
6083       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6084       orntNew[2] = -2;
6085       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6086       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6087 #if 1
6088       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);
6089       for (p = 0; p < 3; ++p) {
6090         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);
6091       }
6092 #endif
6093       /* C triangle */
6094       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6095       orntNew[0] = -2;
6096       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6097       orntNew[1] = ornt[1];
6098       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6099       orntNew[2] = ornt[2];
6100       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6101       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6102 #if 1
6103       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);
6104       for (p = 0; p < 3; ++p) {
6105         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);
6106       }
6107 #endif
6108       /* D triangle */
6109       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6110       orntNew[0] = 0;
6111       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6112       orntNew[1] = 0;
6113       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6114       orntNew[2] = 0;
6115       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6116       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6117 #if 1
6118       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);
6119       for (p = 0; p < 3; ++p) {
6120         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);
6121       }
6122 #endif
6123     }
6124     /*
6125      2----3----3
6126      |         |
6127      |    B    |
6128      |         |
6129      0----4--- 1
6130      |         |
6131      |    A    |
6132      |         |
6133      0----2----1
6134      */
6135     /* Hybrid cells have 4 faces */
6136     for (c = cMax; c < cEnd; ++c) {
6137       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6138       const PetscInt *cone, *ornt;
6139       PetscInt        coneNew[4], orntNew[4];
6140 
6141       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6142       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6143       /* A quad */
6144       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6145       orntNew[0] = ornt[0];
6146       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6147       orntNew[1] = ornt[1];
6148       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6149       orntNew[2] = 0;
6150       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6151       orntNew[3] = 0;
6152       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6153       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6154 #if 1
6155       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);
6156       for (p = 0; p < 4; ++p) {
6157         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);
6158       }
6159 #endif
6160       /* B quad */
6161       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6162       orntNew[0] = ornt[0];
6163       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6164       orntNew[1] = ornt[1];
6165       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6166       orntNew[2] = 0;
6167       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6168       orntNew[3] = 0;
6169       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6170       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6171 #if 1
6172       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);
6173       for (p = 0; p < 4; ++p) {
6174         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);
6175       }
6176 #endif
6177     }
6178     /* Interior split faces have 2 vertices and the same cells as the parent */
6179     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6180     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6181     for (f = fStart; f < fMax; ++f) {
6182       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6183 
6184       for (r = 0; r < 2; ++r) {
6185         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6186         const PetscInt *cone, *support;
6187         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6188 
6189         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6190         coneNew[0]       = vStartNew + (cone[0] - vStart);
6191         coneNew[1]       = vStartNew + (cone[1] - vStart);
6192         coneNew[(r+1)%2] = newv;
6193         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6194 #if 1
6195         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6196         for (p = 0; p < 2; ++p) {
6197           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);
6198         }
6199 #endif
6200         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6201         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6202         for (s = 0; s < supportSize; ++s) {
6203           if (support[s] >= cMax) {
6204             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6205           } else {
6206             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6207             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6208             for (c = 0; c < coneSize; ++c) {
6209               if (cone[c] == f) break;
6210             }
6211             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6212           }
6213         }
6214         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6215 #if 1
6216         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6217         for (p = 0; p < supportSize; ++p) {
6218           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);
6219         }
6220 #endif
6221       }
6222     }
6223     /* Interior cell faces have 2 vertices and 2 cells */
6224     for (c = cStart; c < cMax; ++c) {
6225       const PetscInt *cone;
6226 
6227       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6228       for (r = 0; r < 3; ++r) {
6229         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6230         PetscInt       coneNew[2];
6231         PetscInt       supportNew[2];
6232 
6233         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6234         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6235         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6236 #if 1
6237         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6238         for (p = 0; p < 2; ++p) {
6239           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);
6240         }
6241 #endif
6242         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6243         supportNew[1] = (c - cStart)*4 + 3;
6244         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6245 #if 1
6246         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6247         for (p = 0; p < 2; ++p) {
6248           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);
6249         }
6250 #endif
6251       }
6252     }
6253     /* Interior hybrid faces have 2 vertices and the same cells */
6254     for (f = fMax; f < fEnd; ++f) {
6255       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6256       const PetscInt *cone;
6257       const PetscInt *support;
6258       PetscInt        coneNew[2];
6259       PetscInt        supportNew[2];
6260       PetscInt        size, s, r;
6261 
6262       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6263       coneNew[0] = vStartNew + (cone[0] - vStart);
6264       coneNew[1] = vStartNew + (cone[1] - vStart);
6265       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6266 #if 1
6267       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6268       for (p = 0; p < 2; ++p) {
6269         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);
6270       }
6271 #endif
6272       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6273       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6274       for (s = 0; s < size; ++s) {
6275         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6276         for (r = 0; r < 2; ++r) {
6277           if (cone[r+2] == f) break;
6278         }
6279         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6280       }
6281       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6282 #if 1
6283       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6284       for (p = 0; p < size; ++p) {
6285         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);
6286       }
6287 #endif
6288     }
6289     /* Cell hybrid faces have 2 vertices and 2 cells */
6290     for (c = cMax; c < cEnd; ++c) {
6291       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6292       const PetscInt *cone;
6293       PetscInt        coneNew[2];
6294       PetscInt        supportNew[2];
6295 
6296       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6297       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6298       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6299       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6300 #if 1
6301       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6302       for (p = 0; p < 2; ++p) {
6303         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);
6304       }
6305 #endif
6306       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6307       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6308       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6309 #if 1
6310       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6311       for (p = 0; p < 2; ++p) {
6312         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);
6313       }
6314 #endif
6315     }
6316     /* Old vertices have identical supports */
6317     for (v = vStart; v < vEnd; ++v) {
6318       const PetscInt  newp = vStartNew + (v - vStart);
6319       const PetscInt *support, *cone;
6320       PetscInt        size, s;
6321 
6322       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6323       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6324       for (s = 0; s < size; ++s) {
6325         if (support[s] >= fMax) {
6326           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6327         } else {
6328           PetscInt r = 0;
6329 
6330           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6331           if (cone[1] == v) r = 1;
6332           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6333         }
6334       }
6335       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6336 #if 1
6337       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6338       for (p = 0; p < size; ++p) {
6339         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);
6340       }
6341 #endif
6342     }
6343     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6344     for (f = fStart; f < fMax; ++f) {
6345       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6346       const PetscInt *cone, *support;
6347       PetscInt        size, newSize = 2, s;
6348 
6349       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6350       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6351       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6352       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6353       for (s = 0; s < size; ++s) {
6354         PetscInt r = 0;
6355 
6356         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6357         if (support[s] >= cMax) {
6358           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6359 
6360           newSize += 1;
6361         } else {
6362           if      (cone[1] == f) r = 1;
6363           else if (cone[2] == f) r = 2;
6364           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6365           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6366 
6367           newSize += 2;
6368         }
6369       }
6370       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6371 #if 1
6372       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6373       for (p = 0; p < newSize; ++p) {
6374         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);
6375       }
6376 #endif
6377     }
6378     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6379     break;
6380   default:
6381     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6382   }
6383   PetscFunctionReturn(0);
6384 }
6385 
6386 #undef __FUNCT__
6387 #define __FUNCT__ "CellRefinerSetCoordinates"
6388 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6389 {
6390   PetscSection   coordSection, coordSectionNew;
6391   Vec            coordinates, coordinatesNew;
6392   PetscScalar   *coords, *coordsNew;
6393   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6394   PetscErrorCode ierr;
6395 
6396   PetscFunctionBegin;
6397   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6398   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6399   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6400   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6401   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6402   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6403   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6404   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6405   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6406   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6407   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6408   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6409   if (fMax < 0) fMax = fEnd;
6410   switch (refiner) {
6411   case 1:
6412   case 2:
6413   case 3:
6414     /* Simplicial and Hex 2D */
6415     /* All vertices have the dim coordinates */
6416     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6417       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6418       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6419     }
6420     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6421     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6422     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6423     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6424     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
6425     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6426     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6427     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6428     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6429     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6430     /* Old vertices have the same coordinates */
6431     for (v = vStart; v < vEnd; ++v) {
6432       const PetscInt newv = vStartNew + (v - vStart);
6433       PetscInt       off, offnew, d;
6434 
6435       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6436       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6437       for (d = 0; d < dim; ++d) {
6438         coordsNew[offnew+d] = coords[off+d];
6439       }
6440     }
6441     /* Face vertices have the average of endpoint coordinates */
6442     for (f = fStart; f < fMax; ++f) {
6443       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6444       const PetscInt *cone;
6445       PetscInt        coneSize, offA, offB, offnew, d;
6446 
6447       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6448       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6449       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6450       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6451       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6452       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6453       for (d = 0; d < dim; ++d) {
6454         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6455       }
6456     }
6457     /* Just Hex 2D */
6458     if (refiner == 2) {
6459       /* Cell vertices have the average of corner coordinates */
6460       for (c = cStart; c < cEnd; ++c) {
6461         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6462         PetscInt      *cone = NULL;
6463         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6464 
6465         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6466         for (p = 0; p < closureSize*2; p += 2) {
6467           const PetscInt point = cone[p];
6468           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6469         }
6470         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6471         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6472         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6473         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6474         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6475         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6476         for (d = 0; d < dim; ++d) {
6477           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6478         }
6479         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6480       }
6481     }
6482     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6483     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6484     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6485     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6486     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
6487     break;
6488   default:
6489     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6490   }
6491   PetscFunctionReturn(0);
6492 }
6493 
6494 #undef __FUNCT__
6495 #define __FUNCT__ "DMPlexCreateProcessSF"
6496 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6497 {
6498   PetscInt           numRoots, numLeaves, l;
6499   const PetscInt    *localPoints;
6500   const PetscSFNode *remotePoints;
6501   PetscInt          *localPointsNew;
6502   PetscSFNode       *remotePointsNew;
6503   PetscInt          *ranks, *ranksNew;
6504   PetscErrorCode     ierr;
6505 
6506   PetscFunctionBegin;
6507   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6508   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6509   for (l = 0; l < numLeaves; ++l) {
6510     ranks[l] = remotePoints[l].rank;
6511   }
6512   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6513   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6514   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6515   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6516   for (l = 0; l < numLeaves; ++l) {
6517     ranksNew[l]              = ranks[l];
6518     localPointsNew[l]        = l;
6519     remotePointsNew[l].index = 0;
6520     remotePointsNew[l].rank  = ranksNew[l];
6521   }
6522   ierr = PetscFree(ranks);CHKERRQ(ierr);
6523   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6524   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
6525   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6526   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6527   PetscFunctionReturn(0);
6528 }
6529 
6530 #undef __FUNCT__
6531 #define __FUNCT__ "CellRefinerCreateSF"
6532 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6533 {
6534   PetscSF            sf, sfNew, sfProcess;
6535   IS                 processRanks;
6536   MPI_Datatype       depthType;
6537   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6538   const PetscInt    *localPoints, *neighbors;
6539   const PetscSFNode *remotePoints;
6540   PetscInt          *localPointsNew;
6541   PetscSFNode       *remotePointsNew;
6542   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6543   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6544   PetscErrorCode     ierr;
6545 
6546   PetscFunctionBegin;
6547   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6548   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6549   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6550   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6551   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6552   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6553   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6554   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6555   switch (refiner) {
6556   case 3:
6557     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6558     cMax = PetscMin(cEnd, cMax);
6559     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6560     fMax = PetscMin(fEnd, fMax);
6561   }
6562   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6563   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6564   /* Caculate size of new SF */
6565   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6566   if (numRoots < 0) PetscFunctionReturn(0);
6567   for (l = 0; l < numLeaves; ++l) {
6568     const PetscInt p = localPoints[l];
6569 
6570     switch (refiner) {
6571     case 1:
6572       /* Simplicial 2D */
6573       if ((p >= vStart) && (p < vEnd)) {
6574         /* Old vertices stay the same */
6575         ++numLeavesNew;
6576       } else if ((p >= fStart) && (p < fEnd)) {
6577         /* Old faces add new faces and vertex */
6578         numLeavesNew += 1 + 2;
6579       } else if ((p >= cStart) && (p < cEnd)) {
6580         /* Old cells add new cells and interior faces */
6581         numLeavesNew += 4 + 3;
6582       }
6583       break;
6584     case 2:
6585       /* Hex 2D */
6586       if ((p >= vStart) && (p < vEnd)) {
6587         /* Old vertices stay the same */
6588         ++numLeavesNew;
6589       } else if ((p >= fStart) && (p < fEnd)) {
6590         /* Old faces add new faces and vertex */
6591         numLeavesNew += 1 + 2;
6592       } else if ((p >= cStart) && (p < cEnd)) {
6593         /* Old cells add new cells and interior faces */
6594         numLeavesNew += 4 + 4;
6595       }
6596       break;
6597     default:
6598       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6599     }
6600   }
6601   /* Communicate depthSizes for each remote rank */
6602   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6603   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6604   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6605   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);
6606   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6607   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6608   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6609   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6610   for (n = 0; n < numNeighbors; ++n) {
6611     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6612   }
6613   depthSizeOld[depth]   = cMax;
6614   depthSizeOld[0]       = vMax;
6615   depthSizeOld[depth-1] = fMax;
6616   depthSizeOld[1]       = eMax;
6617 
6618   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6619   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6620 
6621   depthSizeOld[depth]   = cEnd - cStart;
6622   depthSizeOld[0]       = vEnd - vStart;
6623   depthSizeOld[depth-1] = fEnd - fStart;
6624   depthSizeOld[1]       = eEnd - eStart;
6625 
6626   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6627   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6628   for (n = 0; n < numNeighbors; ++n) {
6629     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6630   }
6631   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6632   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6633   /* Calculate new point SF */
6634   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6635   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6636   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6637   for (l = 0, m = 0; l < numLeaves; ++l) {
6638     PetscInt    p     = localPoints[l];
6639     PetscInt    rp    = remotePoints[l].index, n;
6640     PetscMPIInt rrank = remotePoints[l].rank;
6641 
6642     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6643     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6644     switch (refiner) {
6645     case 1:
6646       /* Simplicial 2D */
6647       if ((p >= vStart) && (p < vEnd)) {
6648         /* Old vertices stay the same */
6649         localPointsNew[m]        = vStartNew     + (p  - vStart);
6650         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6651         remotePointsNew[m].rank  = rrank;
6652         ++m;
6653       } else if ((p >= fStart) && (p < fEnd)) {
6654         /* Old faces add new faces and vertex */
6655         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6656         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6657         remotePointsNew[m].rank  = rrank;
6658         ++m;
6659         for (r = 0; r < 2; ++r, ++m) {
6660           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6661           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6662           remotePointsNew[m].rank  = rrank;
6663         }
6664       } else if ((p >= cStart) && (p < cEnd)) {
6665         /* Old cells add new cells and interior faces */
6666         for (r = 0; r < 4; ++r, ++m) {
6667           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6668           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6669           remotePointsNew[m].rank  = rrank;
6670         }
6671         for (r = 0; r < 3; ++r, ++m) {
6672           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6673           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6674           remotePointsNew[m].rank  = rrank;
6675         }
6676       }
6677       break;
6678     case 2:
6679       /* Hex 2D */
6680       if ((p >= vStart) && (p < vEnd)) {
6681         /* Old vertices stay the same */
6682         localPointsNew[m]        = vStartNew     + (p  - vStart);
6683         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6684         remotePointsNew[m].rank  = rrank;
6685         ++m;
6686       } else if ((p >= fStart) && (p < fEnd)) {
6687         /* Old faces add new faces and vertex */
6688         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6689         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6690         remotePointsNew[m].rank  = rrank;
6691         ++m;
6692         for (r = 0; r < 2; ++r, ++m) {
6693           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6694           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6695           remotePointsNew[m].rank  = rrank;
6696         }
6697       } else if ((p >= cStart) && (p < cEnd)) {
6698         /* Old cells add new cells and interior faces */
6699         for (r = 0; r < 4; ++r, ++m) {
6700           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6701           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6702           remotePointsNew[m].rank  = rrank;
6703         }
6704         for (r = 0; r < 4; ++r, ++m) {
6705           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6706           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6707           remotePointsNew[m].rank  = rrank;
6708         }
6709       }
6710       break;
6711     case 3:
6712       /* Hybrid simplicial 2D */
6713       if ((p >= vStart) && (p < vEnd)) {
6714         /* Old vertices stay the same */
6715         localPointsNew[m]        = vStartNew     + (p  - vStart);
6716         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6717         remotePointsNew[m].rank  = rrank;
6718         ++m;
6719       } else if ((p >= fStart) && (p < fMax)) {
6720         /* Old interior faces add new faces and vertex */
6721         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6722         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6723         remotePointsNew[m].rank  = rrank;
6724         ++m;
6725         for (r = 0; r < 2; ++r, ++m) {
6726           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6727           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6728           remotePointsNew[m].rank  = rrank;
6729         }
6730       } else if ((p >= fMax) && (p < fEnd)) {
6731         /* Old hybrid faces stay the same */
6732         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6733         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6734         remotePointsNew[m].rank  = rrank;
6735         ++m;
6736       } else if ((p >= cStart) && (p < cMax)) {
6737         /* Old interior cells add new cells and interior faces */
6738         for (r = 0; r < 4; ++r, ++m) {
6739           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6740           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6741           remotePointsNew[m].rank  = rrank;
6742         }
6743         for (r = 0; r < 3; ++r, ++m) {
6744           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6745           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6746           remotePointsNew[m].rank  = rrank;
6747         }
6748       } else if ((p >= cStart) && (p < cMax)) {
6749         /* Old hybrid cells add new cells and hybrid face */
6750         for (r = 0; r < 2; ++r, ++m) {
6751           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6752           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6753           remotePointsNew[m].rank  = rrank;
6754         }
6755         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6756         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]);
6757         remotePointsNew[m].rank  = rrank;
6758         ++m;
6759       }
6760       break;
6761     default:
6762       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6763     }
6764   }
6765   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6766   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6767   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6768   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6769   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6770   PetscFunctionReturn(0);
6771 }
6772 
6773 #undef __FUNCT__
6774 #define __FUNCT__ "CellRefinerCreateLabels"
6775 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6776 {
6777   PetscInt       numLabels, l;
6778   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
6779   PetscErrorCode ierr;
6780 
6781   PetscFunctionBegin;
6782   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6783   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6784   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6785   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6786 
6787   cStartNew = 0;
6788   vStartNew = depthSize[2];
6789   fStartNew = depthSize[2] + depthSize[0];
6790 
6791   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6792   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6793   switch (refiner) {
6794   case 3:
6795     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6796     cMax = PetscMin(cEnd, cMax);
6797     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6798     fMax = PetscMin(fEnd, fMax);
6799   }
6800   for (l = 0; l < numLabels; ++l) {
6801     DMLabel         label, labelNew;
6802     const char     *lname;
6803     PetscBool       isDepth;
6804     IS              valueIS;
6805     const PetscInt *values;
6806     PetscInt        numValues, val;
6807 
6808     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6809     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6810     if (isDepth) continue;
6811     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6812     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6813     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6814     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6815     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6816     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6817     for (val = 0; val < numValues; ++val) {
6818       IS              pointIS;
6819       const PetscInt *points;
6820       PetscInt        numPoints, n;
6821 
6822       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6823       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6824       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6825       for (n = 0; n < numPoints; ++n) {
6826         const PetscInt p = points[n];
6827         switch (refiner) {
6828         case 1:
6829           /* Simplicial 2D */
6830           if ((p >= vStart) && (p < vEnd)) {
6831             /* Old vertices stay the same */
6832             newp = vStartNew + (p - vStart);
6833             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6834           } else if ((p >= fStart) && (p < fEnd)) {
6835             /* Old faces add new faces and vertex */
6836             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6837             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6838             for (r = 0; r < 2; ++r) {
6839               newp = fStartNew + (p - fStart)*2 + r;
6840               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6841             }
6842           } else if ((p >= cStart) && (p < cEnd)) {
6843             /* Old cells add new cells and interior faces */
6844             for (r = 0; r < 4; ++r) {
6845               newp = cStartNew + (p - cStart)*4 + r;
6846               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6847             }
6848             for (r = 0; r < 3; ++r) {
6849               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6850               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6851             }
6852           }
6853           break;
6854         case 2:
6855           /* Hex 2D */
6856           if ((p >= vStart) && (p < vEnd)) {
6857             /* Old vertices stay the same */
6858             newp = vStartNew + (p - vStart);
6859             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6860           } else if ((p >= fStart) && (p < fEnd)) {
6861             /* Old faces add new faces and vertex */
6862             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6863             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6864             for (r = 0; r < 2; ++r) {
6865               newp = fStartNew + (p - fStart)*2 + r;
6866               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6867             }
6868           } else if ((p >= cStart) && (p < cEnd)) {
6869             /* Old cells add new cells and interior faces and vertex */
6870             for (r = 0; r < 4; ++r) {
6871               newp = cStartNew + (p - cStart)*4 + r;
6872               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6873             }
6874             for (r = 0; r < 4; ++r) {
6875               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6876               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6877             }
6878             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6879             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6880           }
6881           break;
6882         case 3:
6883           /* Hybrid simplicial 2D */
6884           if ((p >= vStart) && (p < vEnd)) {
6885             /* Old vertices stay the same */
6886             newp = vStartNew + (p - vStart);
6887             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6888           } else if ((p >= fStart) && (p < fMax)) {
6889             /* Old interior faces add new faces and vertex */
6890             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6891             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6892             for (r = 0; r < 2; ++r) {
6893               newp = fStartNew + (p - fStart)*2 + r;
6894               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6895             }
6896           } else if ((p >= fMax) && (p < fEnd)) {
6897             /* Old hybrid faces stay the same */
6898             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6899             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6900           } else if ((p >= cStart) && (p < cMax)) {
6901             /* Old interior cells add new cells and interior faces */
6902             for (r = 0; r < 4; ++r) {
6903               newp = cStartNew + (p - cStart)*4 + r;
6904               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6905             }
6906             for (r = 0; r < 3; ++r) {
6907               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6908               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6909             }
6910           } else if ((p >= cMax) && (p < cEnd)) {
6911             /* Old hybrid cells add new cells and hybrid face */
6912             for (r = 0; r < 2; ++r) {
6913               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6914               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6915             }
6916             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6917             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6918           }
6919           break;
6920         default:
6921           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6922         }
6923       }
6924       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6925       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6926     }
6927     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6928     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6929     if (0) {
6930       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6931       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6932       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6933     }
6934   }
6935   PetscFunctionReturn(0);
6936 }
6937 
6938 #undef __FUNCT__
6939 #define __FUNCT__ "DMPlexRefine_Uniform"
6940 /* This will only work for interpolated meshes */
6941 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6942 {
6943   DM             rdm;
6944   PetscInt      *depthSize;
6945   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6946   PetscErrorCode ierr;
6947 
6948   PetscFunctionBegin;
6949   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6950   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6951   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6952   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6953   /* Calculate number of new points of each depth */
6954   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6955   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
6956   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6957   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6958   /* Step 1: Set chart */
6959   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6960   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6961   /* Step 2: Set cone/support sizes */
6962   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6963   /* Step 3: Setup refined DM */
6964   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6965   /* Step 4: Set cones and supports */
6966   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6967   /* Step 5: Stratify */
6968   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6969   /* Step 6: Set coordinates for vertices */
6970   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6971   /* Step 7: Create pointSF */
6972   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6973   /* Step 8: Create labels */
6974   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6975   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6976 
6977   *dmRefined = rdm;
6978   PetscFunctionReturn(0);
6979 }
6980 
6981 #undef __FUNCT__
6982 #define __FUNCT__ "DMPlexSetRefinementUniform"
6983 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6984 {
6985   DM_Plex *mesh = (DM_Plex*) dm->data;
6986 
6987   PetscFunctionBegin;
6988   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6989   mesh->refinementUniform = refinementUniform;
6990   PetscFunctionReturn(0);
6991 }
6992 
6993 #undef __FUNCT__
6994 #define __FUNCT__ "DMPlexGetRefinementUniform"
6995 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6996 {
6997   DM_Plex *mesh = (DM_Plex*) dm->data;
6998 
6999   PetscFunctionBegin;
7000   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7001   PetscValidPointer(refinementUniform,  2);
7002   *refinementUniform = mesh->refinementUniform;
7003   PetscFunctionReturn(0);
7004 }
7005 
7006 #undef __FUNCT__
7007 #define __FUNCT__ "DMPlexSetRefinementLimit"
7008 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7009 {
7010   DM_Plex *mesh = (DM_Plex*) dm->data;
7011 
7012   PetscFunctionBegin;
7013   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7014   mesh->refinementLimit = refinementLimit;
7015   PetscFunctionReturn(0);
7016 }
7017 
7018 #undef __FUNCT__
7019 #define __FUNCT__ "DMPlexGetRefinementLimit"
7020 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7021 {
7022   DM_Plex *mesh = (DM_Plex*) dm->data;
7023 
7024   PetscFunctionBegin;
7025   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7026   PetscValidPointer(refinementLimit,  2);
7027   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7028   *refinementLimit = mesh->refinementLimit;
7029   PetscFunctionReturn(0);
7030 }
7031 
7032 #undef __FUNCT__
7033 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7034 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7035 {
7036   PetscInt       dim, cStart, coneSize, cMax;
7037   PetscErrorCode ierr;
7038 
7039   PetscFunctionBegin;
7040   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7041   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7042   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7043   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7044   switch (dim) {
7045   case 2:
7046     switch (coneSize) {
7047     case 3:
7048       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7049       else *cellRefiner = 1; /* Triangular */
7050       break;
7051     case 4:
7052       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7053       else *cellRefiner = 2; /* Quadrilateral */
7054       break;
7055     default:
7056       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7057     }
7058     break;
7059   default:
7060     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7061   }
7062   PetscFunctionReturn(0);
7063 }
7064 
7065 #undef __FUNCT__
7066 #define __FUNCT__ "DMRefine_Plex"
7067 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7068 {
7069   PetscReal      refinementLimit;
7070   PetscInt       dim, cStart, cEnd;
7071   char           genname[1024], *name = NULL;
7072   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7073   PetscErrorCode ierr;
7074 
7075   PetscFunctionBegin;
7076   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7077   if (isUniform) {
7078     CellRefiner cellRefiner;
7079 
7080     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7081     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7082     PetscFunctionReturn(0);
7083   }
7084   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7085   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7086   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7087   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7088   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7089   if (flg) name = genname;
7090   if (name) {
7091     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7092     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7093     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7094   }
7095   switch (dim) {
7096   case 2:
7097     if (!name || isTriangle) {
7098 #if defined(PETSC_HAVE_TRIANGLE)
7099       double  *maxVolumes;
7100       PetscInt c;
7101 
7102       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7103       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7104       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7105 #else
7106       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7107 #endif
7108     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7109     break;
7110   case 3:
7111     if (!name || isCTetgen) {
7112 #if defined(PETSC_HAVE_CTETGEN)
7113       PetscReal *maxVolumes;
7114       PetscInt   c;
7115 
7116       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7117       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7118       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7119 #else
7120       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7121 #endif
7122     } else if (isTetgen) {
7123 #if defined(PETSC_HAVE_TETGEN)
7124       double  *maxVolumes;
7125       PetscInt c;
7126 
7127       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7128       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7129       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7130 #else
7131       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7132 #endif
7133     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7134     break;
7135   default:
7136     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7137   }
7138   PetscFunctionReturn(0);
7139 }
7140 
7141 #undef __FUNCT__
7142 #define __FUNCT__ "DMPlexGetDepth"
7143 /*@
7144   DMPlexGetDepth - get the number of strata
7145 
7146   Not Collective
7147 
7148   Input Parameters:
7149 . dm           - The DMPlex object
7150 
7151   Output Parameters:
7152 . depth - number of strata
7153 
7154   Level: developer
7155 
7156   Notes:
7157   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7158 
7159 .keywords: mesh, points
7160 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7161 @*/
7162 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7163 {
7164   PetscInt       d;
7165   PetscErrorCode ierr;
7166 
7167   PetscFunctionBegin;
7168   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7169   PetscValidPointer(depth, 2);
7170   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7171   *depth = d-1;
7172   PetscFunctionReturn(0);
7173 }
7174 
7175 #undef __FUNCT__
7176 #define __FUNCT__ "DMPlexGetDepthStratum"
7177 /*@
7178   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7179 
7180   Not Collective
7181 
7182   Input Parameters:
7183 + dm           - The DMPlex object
7184 - stratumValue - The requested depth
7185 
7186   Output Parameters:
7187 + start - The first point at this depth
7188 - end   - One beyond the last point at this depth
7189 
7190   Level: developer
7191 
7192 .keywords: mesh, points
7193 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7194 @*/
7195 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7196 {
7197   DM_Plex       *mesh = (DM_Plex*) dm->data;
7198   DMLabel        next  = mesh->labels;
7199   PetscBool      flg   = PETSC_FALSE;
7200   PetscInt       depth;
7201   PetscErrorCode ierr;
7202 
7203   PetscFunctionBegin;
7204   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7205   if (stratumValue < 0) {
7206     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7207     PetscFunctionReturn(0);
7208   } else {
7209     PetscInt pStart, pEnd;
7210 
7211     if (start) *start = 0;
7212     if (end)   *end   = 0;
7213     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7214     if (pStart == pEnd) PetscFunctionReturn(0);
7215   }
7216   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7217   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7218   /* We should have a generic GetLabel() and a Label class */
7219   while (next) {
7220     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7221     if (flg) break;
7222     next = next->next;
7223   }
7224   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7225   depth = stratumValue;
7226   if ((depth < 0) || (depth >= next->numStrata)) {
7227     if (start) *start = 0;
7228     if (end)   *end   = 0;
7229   } else {
7230     if (start) *start = next->points[next->stratumOffsets[depth]];
7231     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7232   }
7233   PetscFunctionReturn(0);
7234 }
7235 
7236 #undef __FUNCT__
7237 #define __FUNCT__ "DMPlexGetHeightStratum"
7238 /*@
7239   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7240 
7241   Not Collective
7242 
7243   Input Parameters:
7244 + dm           - The DMPlex object
7245 - stratumValue - The requested height
7246 
7247   Output Parameters:
7248 + start - The first point at this height
7249 - end   - One beyond the last point at this height
7250 
7251   Level: developer
7252 
7253 .keywords: mesh, points
7254 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7255 @*/
7256 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7257 {
7258   DM_Plex       *mesh = (DM_Plex*) dm->data;
7259   DMLabel        next  = mesh->labels;
7260   PetscBool      flg   = PETSC_FALSE;
7261   PetscInt       depth;
7262   PetscErrorCode ierr;
7263 
7264   PetscFunctionBegin;
7265   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7266   if (stratumValue < 0) {
7267     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7268   } else {
7269     PetscInt pStart, pEnd;
7270 
7271     if (start) *start = 0;
7272     if (end)   *end   = 0;
7273     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7274     if (pStart == pEnd) PetscFunctionReturn(0);
7275   }
7276   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7277   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7278   /* We should have a generic GetLabel() and a Label class */
7279   while (next) {
7280     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7281     if (flg) break;
7282     next = next->next;
7283   }
7284   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7285   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7286   if ((depth < 0) || (depth >= next->numStrata)) {
7287     if (start) *start = 0;
7288     if (end)   *end   = 0;
7289   } else {
7290     if (start) *start = next->points[next->stratumOffsets[depth]];
7291     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7292   }
7293   PetscFunctionReturn(0);
7294 }
7295 
7296 #undef __FUNCT__
7297 #define __FUNCT__ "DMPlexCreateSectionInitial"
7298 /* Set the number of dof on each point and separate by fields */
7299 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7300 {
7301   PetscInt      *numDofTot;
7302   PetscInt       pStart = 0, pEnd = 0;
7303   PetscInt       p, d, f;
7304   PetscErrorCode ierr;
7305 
7306   PetscFunctionBegin;
7307   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7308   for (d = 0; d <= dim; ++d) {
7309     numDofTot[d] = 0;
7310     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7311   }
7312   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
7313   if (numFields > 0) {
7314     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7315     if (numComp) {
7316       for (f = 0; f < numFields; ++f) {
7317         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7318       }
7319     }
7320   }
7321   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7322   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7323   for (d = 0; d <= dim; ++d) {
7324     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7325     for (p = pStart; p < pEnd; ++p) {
7326       for (f = 0; f < numFields; ++f) {
7327         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7328       }
7329       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7330     }
7331   }
7332   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7333   PetscFunctionReturn(0);
7334 }
7335 
7336 #undef __FUNCT__
7337 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7338 /* Set the number of dof on each point and separate by fields
7339    If constDof is PETSC_DETERMINE, constrain every dof on the point
7340 */
7341 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7342 {
7343   PetscInt       numFields;
7344   PetscInt       bc;
7345   PetscErrorCode ierr;
7346 
7347   PetscFunctionBegin;
7348   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7349   for (bc = 0; bc < numBC; ++bc) {
7350     PetscInt        field = 0;
7351     const PetscInt *idx;
7352     PetscInt        n, i;
7353 
7354     if (numFields) field = bcField[bc];
7355     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7356     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7357     for (i = 0; i < n; ++i) {
7358       const PetscInt p        = idx[i];
7359       PetscInt       numConst = constDof;
7360 
7361       /* Constrain every dof on the point */
7362       if (numConst < 0) {
7363         if (numFields) {
7364           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7365         } else {
7366           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7367         }
7368       }
7369       if (numFields) {
7370         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7371       }
7372       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7373     }
7374     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7375   }
7376   PetscFunctionReturn(0);
7377 }
7378 
7379 #undef __FUNCT__
7380 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7381 /* Set the constrained indices on each point and separate by fields */
7382 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7383 {
7384   PetscInt      *maxConstraints;
7385   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7386   PetscErrorCode ierr;
7387 
7388   PetscFunctionBegin;
7389   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7390   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7391   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7392   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7393   for (p = pStart; p < pEnd; ++p) {
7394     PetscInt cdof;
7395 
7396     if (numFields) {
7397       for (f = 0; f < numFields; ++f) {
7398         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7399         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7400       }
7401     } else {
7402       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7403       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7404     }
7405   }
7406   for (f = 0; f < numFields; ++f) {
7407     maxConstraints[numFields] += maxConstraints[f];
7408   }
7409   if (maxConstraints[numFields]) {
7410     PetscInt *indices;
7411 
7412     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7413     for (p = pStart; p < pEnd; ++p) {
7414       PetscInt cdof, d;
7415 
7416       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7417       if (cdof) {
7418         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7419         if (numFields) {
7420           PetscInt numConst = 0, foff = 0;
7421 
7422           for (f = 0; f < numFields; ++f) {
7423             PetscInt cfdof, fdof;
7424 
7425             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7426             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7427             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7428             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7429             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7430             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7431             numConst += cfdof;
7432             foff     += fdof;
7433           }
7434           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7435         } else {
7436           for (d = 0; d < cdof; ++d) indices[d] = d;
7437         }
7438         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7439       }
7440     }
7441     ierr = PetscFree(indices);CHKERRQ(ierr);
7442   }
7443   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7444   PetscFunctionReturn(0);
7445 }
7446 
7447 #undef __FUNCT__
7448 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7449 /* Set the constrained field indices on each point */
7450 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7451 {
7452   const PetscInt *points, *indices;
7453   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7454   PetscErrorCode  ierr;
7455 
7456   PetscFunctionBegin;
7457   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7458   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7459 
7460   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7461   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7462   if (!constraintIndices) {
7463     PetscInt *idx, i;
7464 
7465     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7466     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7467     for (i = 0; i < maxDof; ++i) idx[i] = i;
7468     for (p = 0; p < numPoints; ++p) {
7469       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7470     }
7471     ierr = PetscFree(idx);CHKERRQ(ierr);
7472   } else {
7473     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7474     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7475     for (p = 0; p < numPoints; ++p) {
7476       PetscInt fcdof;
7477 
7478       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7479       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);
7480       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7481     }
7482     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7483   }
7484   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7485   PetscFunctionReturn(0);
7486 }
7487 
7488 #undef __FUNCT__
7489 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7490 /* Set the constrained indices on each point and separate by fields */
7491 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7492 {
7493   PetscInt      *indices;
7494   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7495   PetscErrorCode ierr;
7496 
7497   PetscFunctionBegin;
7498   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7499   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7500   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7501   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7502   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7503   for (p = pStart; p < pEnd; ++p) {
7504     PetscInt cdof, d;
7505 
7506     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7507     if (cdof) {
7508       PetscInt numConst = 0, foff = 0;
7509 
7510       for (f = 0; f < numFields; ++f) {
7511         const PetscInt *fcind;
7512         PetscInt        fdof, fcdof;
7513 
7514         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7515         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7516         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7517         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7518         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
7519         foff     += fdof;
7520         numConst += fcdof;
7521       }
7522       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7523       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7524     }
7525   }
7526   ierr = PetscFree(indices);CHKERRQ(ierr);
7527   PetscFunctionReturn(0);
7528 }
7529 
7530 #undef __FUNCT__
7531 #define __FUNCT__ "DMPlexCreateSection"
7532 /*@C
7533   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7534 
7535   Not Collective
7536 
7537   Input Parameters:
7538 + dm        - The DMPlex object
7539 . dim       - The spatial dimension of the problem
7540 . numFields - The number of fields in the problem
7541 . numComp   - An array of size numFields that holds the number of components for each field
7542 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7543 . numBC     - The number of boundary conditions
7544 . bcField   - An array of size numBC giving the field number for each boundry condition
7545 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7546 
7547   Output Parameter:
7548 . section - The PetscSection object
7549 
7550   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
7551   nubmer of dof for field 0 on each edge.
7552 
7553   Level: developer
7554 
7555 .keywords: mesh, elements
7556 .seealso: DMPlexCreate(), PetscSectionCreate()
7557 @*/
7558 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
7559 {
7560   PetscErrorCode ierr;
7561 
7562   PetscFunctionBegin;
7563   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7564   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7565   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7566   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7567   {
7568     PetscBool view = PETSC_FALSE;
7569 
7570     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7571     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7572   }
7573   PetscFunctionReturn(0);
7574 }
7575 
7576 #undef __FUNCT__
7577 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7578 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
7579 {
7580   PetscSection   section;
7581   PetscErrorCode ierr;
7582 
7583   PetscFunctionBegin;
7584   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7585   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7586   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7587   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7588   PetscFunctionReturn(0);
7589 }
7590 
7591 #undef __FUNCT__
7592 #define __FUNCT__ "DMPlexGetCoordinateSection"
7593 /*@
7594   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7595 
7596   Not Collective
7597 
7598   Input Parameter:
7599 . dm - The DMPlex object
7600 
7601   Output Parameter:
7602 . section - The PetscSection object
7603 
7604   Level: intermediate
7605 
7606 .keywords: mesh, coordinates
7607 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7608 @*/
7609 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
7610 {
7611   DM             cdm;
7612   PetscErrorCode ierr;
7613 
7614   PetscFunctionBegin;
7615   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7616   PetscValidPointer(section, 2);
7617   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7618   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7619   PetscFunctionReturn(0);
7620 }
7621 
7622 #undef __FUNCT__
7623 #define __FUNCT__ "DMPlexSetCoordinateSection"
7624 /*@
7625   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7626 
7627   Not Collective
7628 
7629   Input Parameters:
7630 + dm      - The DMPlex object
7631 - section - The PetscSection object
7632 
7633   Level: intermediate
7634 
7635 .keywords: mesh, coordinates
7636 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7637 @*/
7638 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
7639 {
7640   DM             cdm;
7641   PetscErrorCode ierr;
7642 
7643   PetscFunctionBegin;
7644   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7645   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
7646   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7647   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7648   PetscFunctionReturn(0);
7649 }
7650 
7651 #undef __FUNCT__
7652 #define __FUNCT__ "DMPlexGetConeSection"
7653 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
7654 {
7655   DM_Plex *mesh = (DM_Plex*) dm->data;
7656 
7657   PetscFunctionBegin;
7658   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7659   if (section) *section = mesh->coneSection;
7660   PetscFunctionReturn(0);
7661 }
7662 
7663 #undef __FUNCT__
7664 #define __FUNCT__ "DMPlexGetCones"
7665 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
7666 {
7667   DM_Plex *mesh = (DM_Plex*) dm->data;
7668 
7669   PetscFunctionBegin;
7670   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7671   if (cones) *cones = mesh->cones;
7672   PetscFunctionReturn(0);
7673 }
7674 
7675 #undef __FUNCT__
7676 #define __FUNCT__ "DMPlexGetConeOrientations"
7677 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
7678 {
7679   DM_Plex *mesh = (DM_Plex*) dm->data;
7680 
7681   PetscFunctionBegin;
7682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7683   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7684   PetscFunctionReturn(0);
7685 }
7686 
7687 #undef __FUNCT__
7688 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7689 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7690 {
7691   const PetscInt embedDim = 2;
7692   PetscReal      x        = PetscRealPart(point[0]);
7693   PetscReal      y        = PetscRealPart(point[1]);
7694   PetscReal      v0[2], J[4], invJ[4], detJ;
7695   PetscReal      xi, eta;
7696   PetscErrorCode ierr;
7697 
7698   PetscFunctionBegin;
7699   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7700   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7701   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7702 
7703   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
7704   else *cell = -1;
7705   PetscFunctionReturn(0);
7706 }
7707 
7708 #undef __FUNCT__
7709 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7710 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7711 {
7712   PetscSection       coordSection;
7713   Vec                coordsLocal;
7714   const PetscScalar *coords;
7715   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7716   PetscReal          x         = PetscRealPart(point[0]);
7717   PetscReal          y         = PetscRealPart(point[1]);
7718   PetscInt           crossings = 0, f;
7719   PetscErrorCode     ierr;
7720 
7721   PetscFunctionBegin;
7722   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7723   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7724   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7725   for (f = 0; f < 4; ++f) {
7726     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7727     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7728     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7729     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7730     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7731     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7732     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7733     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7734     if ((cond1 || cond2)  && above) ++crossings;
7735   }
7736   if (crossings % 2) *cell = c;
7737   else *cell = -1;
7738   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7739   PetscFunctionReturn(0);
7740 }
7741 
7742 #undef __FUNCT__
7743 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7744 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7745 {
7746   const PetscInt embedDim = 3;
7747   PetscReal      v0[3], J[9], invJ[9], detJ;
7748   PetscReal      x = PetscRealPart(point[0]);
7749   PetscReal      y = PetscRealPart(point[1]);
7750   PetscReal      z = PetscRealPart(point[2]);
7751   PetscReal      xi, eta, zeta;
7752   PetscErrorCode ierr;
7753 
7754   PetscFunctionBegin;
7755   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7756   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
7757   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
7758   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
7759 
7760   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
7761   else *cell = -1;
7762   PetscFunctionReturn(0);
7763 }
7764 
7765 #undef __FUNCT__
7766 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7767 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7768 {
7769   PetscSection       coordSection;
7770   Vec                coordsLocal;
7771   const PetscScalar *coords;
7772   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7773                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7774   PetscBool          found = PETSC_TRUE;
7775   PetscInt           f;
7776   PetscErrorCode     ierr;
7777 
7778   PetscFunctionBegin;
7779   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7780   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7781   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7782   for (f = 0; f < 6; ++f) {
7783     /* Check the point is under plane */
7784     /*   Get face normal */
7785     PetscReal v_i[3];
7786     PetscReal v_j[3];
7787     PetscReal normal[3];
7788     PetscReal pp[3];
7789     PetscReal dot;
7790 
7791     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
7792     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
7793     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
7794     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
7795     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
7796     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
7797     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
7798     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
7799     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
7800     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
7801     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
7802     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
7803     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7804 
7805     /* Check that projected point is in face (2D location problem) */
7806     if (dot < 0.0) {
7807       found = PETSC_FALSE;
7808       break;
7809     }
7810   }
7811   if (found) *cell = c;
7812   else *cell = -1;
7813   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7814   PetscFunctionReturn(0);
7815 }
7816 
7817 #undef __FUNCT__
7818 #define __FUNCT__ "DMLocatePoints_Plex"
7819 /*
7820  Need to implement using the guess
7821 */
7822 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7823 {
7824   PetscInt       cell = -1 /*, guess = -1*/;
7825   PetscInt       bs, numPoints, p;
7826   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7827   PetscInt      *cells;
7828   PetscScalar   *a;
7829   PetscErrorCode ierr;
7830 
7831   PetscFunctionBegin;
7832   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7833   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7834   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7835   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7836   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7837   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7838   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7839   if (bs != dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
7840   numPoints /= bs;
7841   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7842   for (p = 0; p < numPoints; ++p) {
7843     const PetscScalar *point = &a[p*bs];
7844 
7845     switch (dim) {
7846     case 2:
7847       for (c = cStart; c < cEnd; ++c) {
7848         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7849         switch (coneSize) {
7850         case 3:
7851           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7852           break;
7853         case 4:
7854           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7855           break;
7856         default:
7857           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7858         }
7859         if (cell >= 0) break;
7860       }
7861       break;
7862     case 3:
7863       for (c = cStart; c < cEnd; ++c) {
7864         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7865         switch (coneSize) {
7866         case 4:
7867           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
7868           break;
7869         case 8:
7870           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
7871           break;
7872         default:
7873           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7874         }
7875         if (cell >= 0) break;
7876       }
7877       break;
7878     default:
7879       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
7880     }
7881     cells[p] = cell;
7882   }
7883   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
7884   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
7885   PetscFunctionReturn(0);
7886 }
7887 
7888 /******************************** FEM Support **********************************/
7889 
7890 #undef __FUNCT__
7891 #define __FUNCT__ "DMPlexVecGetClosure"
7892 /*@C
7893   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
7894 
7895   Not collective
7896 
7897   Input Parameters:
7898 + dm - The DM
7899 . section - The section describing the layout in v, or NULL to use the default section
7900 . v - The local vector
7901 - point - The sieve point in the DM
7902 
7903   Output Parameters:
7904 + csize - The number of values in the closure, or NULL
7905 - values - The array of values, which is a borrowed array and should not be freed
7906 
7907   Level: intermediate
7908 
7909 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7910 @*/
7911 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
7912 {
7913   PetscScalar   *array, *vArray;
7914   PetscInt      *points = NULL;
7915   PetscInt       offsets[32];
7916   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
7917   PetscErrorCode ierr;
7918 
7919   PetscFunctionBegin;
7920   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7921   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7922   if (!section) {
7923     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7924   }
7925   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7926   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7927   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7928   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7929   /* Compress out points not in the section */
7930   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7931   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7932     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7933       points[q*2]   = points[p];
7934       points[q*2+1] = points[p+1];
7935       ++q;
7936     }
7937   }
7938   numPoints = q;
7939   for (p = 0, size = 0; p < numPoints*2; p += 2) {
7940     PetscInt dof, fdof;
7941 
7942     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7943     for (f = 0; f < numFields; ++f) {
7944       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7945       offsets[f+1] += fdof;
7946     }
7947     size += dof;
7948   }
7949   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7950   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
7951   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
7952   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
7953   for (p = 0; p < numPoints*2; p += 2) {
7954     PetscInt     o = points[p+1];
7955     PetscInt     dof, off, d;
7956     PetscScalar *varr;
7957 
7958     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7959     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
7960     varr = &vArray[off];
7961     if (numFields) {
7962       PetscInt fdof, foff, fcomp, f, c;
7963 
7964       for (f = 0, foff = 0; f < numFields; ++f) {
7965         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7966         if (o >= 0) {
7967           for (d = 0; d < fdof; ++d, ++offsets[f]) {
7968             array[offsets[f]] = varr[foff+d];
7969           }
7970         } else {
7971           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7972           for (d = fdof/fcomp-1; d >= 0; --d) {
7973             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
7974               array[offsets[f]] = varr[foff+d*fcomp+c];
7975             }
7976           }
7977         }
7978         foff += fdof;
7979       }
7980     } else {
7981       if (o >= 0) {
7982         for (d = 0; d < dof; ++d, ++offsets[0]) {
7983           array[offsets[0]] = varr[d];
7984         }
7985       } else {
7986         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
7987           array[offsets[0]] = varr[d];
7988         }
7989       }
7990     }
7991   }
7992   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7993   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
7994   if (csize) *csize = size;
7995   *values = array;
7996   PetscFunctionReturn(0);
7997 }
7998 
7999 #undef __FUNCT__
8000 #define __FUNCT__ "DMPlexVecRestoreClosure"
8001 /*@C
8002   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8003 
8004   Not collective
8005 
8006   Input Parameters:
8007 + dm - The DM
8008 . section - The section describing the layout in v, or NULL to use the default section
8009 . v - The local vector
8010 . point - The sieve point in the DM
8011 . csize - The number of values in the closure, or NULL
8012 - values - The array of values, which is a borrowed array and should not be freed
8013 
8014   Level: intermediate
8015 
8016 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8017 @*/
8018 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8019 {
8020   PetscInt       size = 0;
8021   PetscErrorCode ierr;
8022 
8023   PetscFunctionBegin;
8024   /* Should work without recalculating size */
8025   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8026   PetscFunctionReturn(0);
8027 }
8028 
8029 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8030 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8031 
8032 #undef __FUNCT__
8033 #define __FUNCT__ "updatePoint_private"
8034 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8035 {
8036   PetscInt        cdof;   /* The number of constraints on this point */
8037   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8038   PetscScalar    *a;
8039   PetscInt        off, cind = 0, k;
8040   PetscErrorCode  ierr;
8041 
8042   PetscFunctionBegin;
8043   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8044   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8045   a    = &array[off];
8046   if (!cdof || setBC) {
8047     if (orientation >= 0) {
8048       for (k = 0; k < dof; ++k) {
8049         fuse(&a[k], values[k]);
8050       }
8051     } else {
8052       for (k = 0; k < dof; ++k) {
8053         fuse(&a[k], values[dof-k-1]);
8054       }
8055     }
8056   } else {
8057     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8058     if (orientation >= 0) {
8059       for (k = 0; k < dof; ++k) {
8060         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8061         fuse(&a[k], values[k]);
8062       }
8063     } else {
8064       for (k = 0; k < dof; ++k) {
8065         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8066         fuse(&a[k], values[dof-k-1]);
8067       }
8068     }
8069   }
8070   PetscFunctionReturn(0);
8071 }
8072 
8073 #undef __FUNCT__
8074 #define __FUNCT__ "updatePointFields_private"
8075 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8076 {
8077   PetscScalar   *a;
8078   PetscInt       numFields, off, foff, f;
8079   PetscErrorCode ierr;
8080 
8081   PetscFunctionBegin;
8082   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8083   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8084   a    = &array[off];
8085   for (f = 0, foff = 0; f < numFields; ++f) {
8086     PetscInt        fdof, fcomp, fcdof;
8087     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8088     PetscInt        cind = 0, k, c;
8089 
8090     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8091     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8092     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8093     if (!fcdof || setBC) {
8094       if (orientation >= 0) {
8095         for (k = 0; k < fdof; ++k) {
8096           fuse(&a[foff+k], values[foffs[f]+k]);
8097         }
8098       } else {
8099         for (k = fdof/fcomp-1; k >= 0; --k) {
8100           for (c = 0; c < fcomp; ++c) {
8101             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8102           }
8103         }
8104       }
8105     } else {
8106       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8107       if (orientation >= 0) {
8108         for (k = 0; k < fdof; ++k) {
8109           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8110           fuse(&a[foff+k], values[foffs[f]+k]);
8111         }
8112       } else {
8113         for (k = fdof/fcomp-1; k >= 0; --k) {
8114           for (c = 0; c < fcomp; ++c) {
8115             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8116             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8117           }
8118         }
8119       }
8120     }
8121     foff     += fdof;
8122     foffs[f] += fdof;
8123   }
8124   PetscFunctionReturn(0);
8125 }
8126 
8127 #undef __FUNCT__
8128 #define __FUNCT__ "DMPlexVecSetClosure"
8129 /*@C
8130   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8131 
8132   Not collective
8133 
8134   Input Parameters:
8135 + dm - The DM
8136 . section - The section describing the layout in v, or NULL to use the default sectionw
8137 . v - The local vector
8138 . point - The sieve point in the DM
8139 . values - The array of values, which is a borrowed array and should not be freed
8140 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8141 
8142   Level: intermediate
8143 
8144 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8145 @*/
8146 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8147 {
8148   PetscScalar   *array;
8149   PetscInt      *points = NULL;
8150   PetscInt       offsets[32];
8151   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8152   PetscErrorCode ierr;
8153 
8154   PetscFunctionBegin;
8155   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8156   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8157   if (!section) {
8158     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8159   }
8160   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8161   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8162   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8163   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8164   /* Compress out points not in the section */
8165   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8166   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8167     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8168       points[q*2]   = points[p];
8169       points[q*2+1] = points[p+1];
8170       ++q;
8171     }
8172   }
8173   numPoints = q;
8174   for (p = 0; p < numPoints*2; p += 2) {
8175     PetscInt fdof;
8176 
8177     for (f = 0; f < numFields; ++f) {
8178       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8179       offsets[f+1] += fdof;
8180     }
8181   }
8182   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8183   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8184   if (numFields) {
8185     switch (mode) {
8186     case INSERT_VALUES:
8187       for (p = 0; p < numPoints*2; p += 2) {
8188         PetscInt o = points[p+1];
8189         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8190       } break;
8191     case INSERT_ALL_VALUES:
8192       for (p = 0; p < numPoints*2; p += 2) {
8193         PetscInt o = points[p+1];
8194         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8195       } break;
8196     case ADD_VALUES:
8197       for (p = 0; p < numPoints*2; p += 2) {
8198         PetscInt o = points[p+1];
8199         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8200       } break;
8201     case ADD_ALL_VALUES:
8202       for (p = 0; p < numPoints*2; p += 2) {
8203         PetscInt o = points[p+1];
8204         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8205       } break;
8206     default:
8207       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8208     }
8209   } else {
8210     switch (mode) {
8211     case INSERT_VALUES:
8212       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8213         PetscInt o = points[p+1];
8214         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8215         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8216       } break;
8217     case INSERT_ALL_VALUES:
8218       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8219         PetscInt o = points[p+1];
8220         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8221         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8222       } break;
8223     case ADD_VALUES:
8224       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8225         PetscInt o = points[p+1];
8226         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8227         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8228       } break;
8229     case ADD_ALL_VALUES:
8230       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8231         PetscInt o = points[p+1];
8232         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8233         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8234       } break;
8235     default:
8236       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8237     }
8238   }
8239   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8240   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8241   PetscFunctionReturn(0);
8242 }
8243 
8244 #undef __FUNCT__
8245 #define __FUNCT__ "DMPlexPrintMatSetValues"
8246 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8247 {
8248   PetscMPIInt    rank;
8249   PetscInt       i, j;
8250   PetscErrorCode ierr;
8251 
8252   PetscFunctionBegin;
8253   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
8254   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8255   for (i = 0; i < numIndices; i++) {
8256     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8257   }
8258   for (i = 0; i < numIndices; i++) {
8259     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8260     for (j = 0; j < numIndices; j++) {
8261 #if defined(PETSC_USE_COMPLEX)
8262       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8263 #else
8264       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8265 #endif
8266     }
8267     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8268   }
8269   PetscFunctionReturn(0);
8270 }
8271 
8272 #undef __FUNCT__
8273 #define __FUNCT__ "indicesPoint_private"
8274 /* . off - The global offset of this point */
8275 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8276 {
8277   PetscInt        dof;    /* The number of unknowns on this point */
8278   PetscInt        cdof;   /* The number of constraints on this point */
8279   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8280   PetscInt        cind = 0, k;
8281   PetscErrorCode  ierr;
8282 
8283   PetscFunctionBegin;
8284   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8285   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8286   if (!cdof || setBC) {
8287     if (orientation >= 0) {
8288       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8289     } else {
8290       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8291     }
8292   } else {
8293     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8294     if (orientation >= 0) {
8295       for (k = 0; k < dof; ++k) {
8296         if ((cind < cdof) && (k == cdofs[cind])) {
8297           /* Insert check for returning constrained indices */
8298           indices[*loff+k] = -(off+k+1);
8299           ++cind;
8300         } else {
8301           indices[*loff+k] = off+k-cind;
8302         }
8303       }
8304     } else {
8305       for (k = 0; k < dof; ++k) {
8306         if ((cind < cdof) && (k == cdofs[cind])) {
8307           /* Insert check for returning constrained indices */
8308           indices[*loff+dof-k-1] = -(off+k+1);
8309           ++cind;
8310         } else {
8311           indices[*loff+dof-k-1] = off+k-cind;
8312         }
8313       }
8314     }
8315   }
8316   *loff += dof;
8317   PetscFunctionReturn(0);
8318 }
8319 
8320 #undef __FUNCT__
8321 #define __FUNCT__ "indicesPointFields_private"
8322 /* . off - The global offset of this point */
8323 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8324 {
8325   PetscInt       numFields, foff, f;
8326   PetscErrorCode ierr;
8327 
8328   PetscFunctionBegin;
8329   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8330   for (f = 0, foff = 0; f < numFields; ++f) {
8331     PetscInt        fdof, fcomp, cfdof;
8332     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8333     PetscInt        cind = 0, k, c;
8334 
8335     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8336     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8337     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8338     if (!cfdof || setBC) {
8339       if (orientation >= 0) {
8340         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8341       } else {
8342         for (k = fdof/fcomp-1; k >= 0; --k) {
8343           for (c = 0; c < fcomp; ++c) {
8344             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8345           }
8346         }
8347       }
8348     } else {
8349       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8350       if (orientation >= 0) {
8351         for (k = 0; k < fdof; ++k) {
8352           if ((cind < cfdof) && (k == fcdofs[cind])) {
8353             indices[foffs[f]+k] = -(off+foff+k+1);
8354             ++cind;
8355           } else {
8356             indices[foffs[f]+k] = off+foff+k-cind;
8357           }
8358         }
8359       } else {
8360         for (k = fdof/fcomp-1; k >= 0; --k) {
8361           for (c = 0; c < fcomp; ++c) {
8362             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8363               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8364               ++cind;
8365             } else {
8366               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8367             }
8368           }
8369         }
8370       }
8371     }
8372     foff     += fdof - cfdof;
8373     foffs[f] += fdof;
8374   }
8375   PetscFunctionReturn(0);
8376 }
8377 
8378 #undef __FUNCT__
8379 #define __FUNCT__ "DMPlexMatSetClosure"
8380 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8381 {
8382   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8383   PetscInt      *points = NULL;
8384   PetscInt      *indices;
8385   PetscInt       offsets[32];
8386   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8387   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8388   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8389   PetscErrorCode ierr;
8390 
8391   PetscFunctionBegin;
8392   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8393   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8394   if (useDefault) {
8395     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8396   }
8397   if (useGlobalDefault) {
8398     if (useDefault) {
8399       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8400     } else {
8401       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8402     }
8403   }
8404   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8405   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8406   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8407   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8408   /* Compress out points not in the section */
8409   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8410   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8411     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8412       points[q*2]   = points[p];
8413       points[q*2+1] = points[p+1];
8414       ++q;
8415     }
8416   }
8417   numPoints = q;
8418   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8419     PetscInt fdof;
8420 
8421     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8422     for (f = 0; f < numFields; ++f) {
8423       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8424       offsets[f+1] += fdof;
8425     }
8426     numIndices += dof;
8427   }
8428   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8429 
8430   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8431   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8432   if (numFields) {
8433     for (p = 0; p < numPoints*2; p += 2) {
8434       PetscInt o = points[p+1];
8435       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8436       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8437     }
8438   } else {
8439     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8440       PetscInt o = points[p+1];
8441       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8442       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8443     }
8444   }
8445   if (useGlobalDefault && !useDefault) {
8446     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8447   }
8448   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8449   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8450   if (ierr) {
8451     PetscMPIInt    rank;
8452     PetscErrorCode ierr2;
8453 
8454     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
8455     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8456     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8457     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8458     CHKERRQ(ierr);
8459   }
8460   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8461   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8462   PetscFunctionReturn(0);
8463 }
8464 
8465 #undef __FUNCT__
8466 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8467 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8468 {
8469   PetscSection       coordSection;
8470   Vec                coordinates;
8471   const PetscScalar *coords;
8472   const PetscInt     dim = 2;
8473   PetscInt           d, f;
8474   PetscErrorCode     ierr;
8475 
8476   PetscFunctionBegin;
8477   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8478   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8479   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8480   if (v0) {
8481     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8482   }
8483   if (J) {
8484     for (d = 0; d < dim; d++) {
8485       for (f = 0; f < dim; f++) {
8486         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8487       }
8488     }
8489     *detJ = J[0]*J[3] - J[1]*J[2];
8490 #if 0
8491     if (detJ < 0.0) {
8492       const PetscReal xLength = mesh->periodicity[0];
8493 
8494       if (xLength != 0.0) {
8495         PetscReal v0x = coords[0*dim+0];
8496 
8497         if (v0x == 0.0) v0x = v0[0] = xLength;
8498         for (f = 0; f < dim; f++) {
8499           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8500 
8501           J[0*dim+f] = 0.5*(px - v0x);
8502         }
8503       }
8504       detJ = J[0]*J[3] - J[1]*J[2];
8505     }
8506 #endif
8507     PetscLogFlops(8.0 + 3.0);
8508   }
8509   if (invJ) {
8510     const PetscReal invDet = 1.0/(*detJ);
8511 
8512     invJ[0] =  invDet*J[3];
8513     invJ[1] = -invDet*J[1];
8514     invJ[2] = -invDet*J[2];
8515     invJ[3] =  invDet*J[0];
8516     PetscLogFlops(5.0);
8517   }
8518   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8519   PetscFunctionReturn(0);
8520 }
8521 
8522 #undef __FUNCT__
8523 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8524 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8525 {
8526   PetscSection       coordSection;
8527   Vec                coordinates;
8528   const PetscScalar *coords;
8529   const PetscInt     dim = 2;
8530   PetscInt           d, f;
8531   PetscErrorCode     ierr;
8532 
8533   PetscFunctionBegin;
8534   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8535   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8536   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8537   if (v0) {
8538     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8539   }
8540   if (J) {
8541     for (d = 0; d < dim; d++) {
8542       for (f = 0; f < dim; f++) {
8543         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8544       }
8545     }
8546     *detJ = J[0]*J[3] - J[1]*J[2];
8547     PetscLogFlops(8.0 + 3.0);
8548   }
8549   if (invJ) {
8550     const PetscReal invDet = 1.0/(*detJ);
8551 
8552     invJ[0] =  invDet*J[3];
8553     invJ[1] = -invDet*J[1];
8554     invJ[2] = -invDet*J[2];
8555     invJ[3] =  invDet*J[0];
8556     PetscLogFlops(5.0);
8557   }
8558   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8559   PetscFunctionReturn(0);
8560 }
8561 
8562 #undef __FUNCT__
8563 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8564 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8565 {
8566   PetscSection       coordSection;
8567   Vec                coordinates;
8568   const PetscScalar *coords;
8569   const PetscInt     dim = 3;
8570   PetscInt           d, f;
8571   PetscErrorCode     ierr;
8572 
8573   PetscFunctionBegin;
8574   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8575   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8576   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8577   if (v0) {
8578     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8579   }
8580   if (J) {
8581     for (d = 0; d < dim; d++) {
8582       for (f = 0; f < dim; f++) {
8583         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8584       }
8585     }
8586     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8587     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8588              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8589              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8590     PetscLogFlops(18.0 + 12.0);
8591   }
8592   if (invJ) {
8593     const PetscReal invDet = 1.0/(*detJ);
8594 
8595     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8596     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8597     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8598     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8599     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8600     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8601     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8602     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8603     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8604     PetscLogFlops(37.0);
8605   }
8606   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8607   PetscFunctionReturn(0);
8608 }
8609 
8610 #undef __FUNCT__
8611 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8612 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8613 {
8614   PetscSection       coordSection;
8615   Vec                coordinates;
8616   const PetscScalar *coords;
8617   const PetscInt     dim = 3;
8618   PetscInt           d;
8619   PetscErrorCode     ierr;
8620 
8621   PetscFunctionBegin;
8622   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8623   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8624   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8625   if (v0) {
8626     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8627   }
8628   if (J) {
8629     for (d = 0; d < dim; d++) {
8630       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8631       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8632       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8633     }
8634     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8635              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8636              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8637     PetscLogFlops(18.0 + 12.0);
8638   }
8639   if (invJ) {
8640     const PetscReal invDet = -1.0/(*detJ);
8641 
8642     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8643     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8644     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8645     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8646     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8647     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8648     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8649     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8650     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8651     PetscLogFlops(37.0);
8652   }
8653   *detJ *= 8.0;
8654   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8655   PetscFunctionReturn(0);
8656 }
8657 
8658 #undef __FUNCT__
8659 #define __FUNCT__ "DMPlexComputeCellGeometry"
8660 /*@C
8661   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8662 
8663   Collective on DM
8664 
8665   Input Arguments:
8666 + dm   - the DM
8667 - cell - the cell
8668 
8669   Output Arguments:
8670 + v0   - the translation part of this affine transform
8671 . J    - the Jacobian of the transform to the reference element
8672 . invJ - the inverse of the Jacobian
8673 - detJ - the Jacobian determinant
8674 
8675   Level: advanced
8676 
8677 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8678 @*/
8679 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
8680 {
8681   PetscInt       dim, coneSize;
8682   PetscErrorCode ierr;
8683 
8684   PetscFunctionBegin;
8685   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8686   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8687   switch (dim) {
8688   case 2:
8689     switch (coneSize) {
8690     case 3:
8691       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8692       break;
8693     case 4:
8694       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8695       break;
8696     default:
8697       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8698     }
8699     break;
8700   case 3:
8701     switch (coneSize) {
8702     case 4:
8703       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8704       break;
8705     case 8:
8706       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8707       break;
8708     default:
8709       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8710     }
8711     break;
8712   default:
8713     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8714   }
8715   PetscFunctionReturn(0);
8716 }
8717 
8718 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8719 {
8720   switch (i) {
8721   case 0:
8722     switch (j) {
8723     case 0: return 0;
8724     case 1:
8725       switch (k) {
8726       case 0: return 0;
8727       case 1: return 0;
8728       case 2: return 1;
8729       }
8730     case 2:
8731       switch (k) {
8732       case 0: return 0;
8733       case 1: return -1;
8734       case 2: return 0;
8735       }
8736     }
8737   case 1:
8738     switch (j) {
8739     case 0:
8740       switch (k) {
8741       case 0: return 0;
8742       case 1: return 0;
8743       case 2: return -1;
8744       }
8745     case 1: return 0;
8746     case 2:
8747       switch (k) {
8748       case 0: return 1;
8749       case 1: return 0;
8750       case 2: return 0;
8751       }
8752     }
8753   case 2:
8754     switch (j) {
8755     case 0:
8756       switch (k) {
8757       case 0: return 0;
8758       case 1: return 1;
8759       case 2: return 0;
8760       }
8761     case 1:
8762       switch (k) {
8763       case 0: return -1;
8764       case 1: return 0;
8765       case 2: return 0;
8766       }
8767     case 2: return 0;
8768     }
8769   }
8770   return 0;
8771 }
8772 
8773 #undef __FUNCT__
8774 #define __FUNCT__ "DMPlexCreateRigidBody"
8775 /*@C
8776   DMPlexCreateRigidBody - create rigid body modes from coordinates
8777 
8778   Collective on DM
8779 
8780   Input Arguments:
8781 + dm - the DM
8782 . section - the local section associated with the rigid field, or NULL for the default section
8783 - globalSection - the global section associated with the rigid field, or NULL for the default section
8784 
8785   Output Argument:
8786 . sp - the null space
8787 
8788   Note: This is necessary to take account of Dirichlet conditions on the displacements
8789 
8790   Level: advanced
8791 
8792 .seealso: MatNullSpaceCreate()
8793 @*/
8794 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8795 {
8796   MPI_Comm       comm;
8797   Vec            coordinates, localMode, mode[6];
8798   PetscSection   coordSection;
8799   PetscScalar   *coords;
8800   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8801   PetscErrorCode ierr;
8802 
8803   PetscFunctionBegin;
8804   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
8805   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8806   if (dim == 1) {
8807     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
8808     PetscFunctionReturn(0);
8809   }
8810   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8811   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8812   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8813   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8814   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8815   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8816   m    = (dim*(dim+1))/2;
8817   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8818   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8819   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8820   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8821   /* Assume P1 */
8822   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8823   for (d = 0; d < dim; ++d) {
8824     PetscScalar values[3] = {0.0, 0.0, 0.0};
8825 
8826     values[d] = 1.0;
8827     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
8828     for (v = vStart; v < vEnd; ++v) {
8829       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8830     }
8831     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8832     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8833   }
8834   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8835   for (d = dim; d < dim*(dim+1)/2; ++d) {
8836     PetscInt i, j, k = dim > 2 ? d - dim : d;
8837 
8838     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8839     for (v = vStart; v < vEnd; ++v) {
8840       PetscScalar values[3] = {0.0, 0.0, 0.0};
8841       PetscInt    off;
8842 
8843       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8844       for (i = 0; i < dim; ++i) {
8845         for (j = 0; j < dim; ++j) {
8846           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
8847         }
8848       }
8849       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8850     }
8851     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8852     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8853   }
8854   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8855   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
8856   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
8857   /* Orthonormalize system */
8858   for (i = dim; i < m; ++i) {
8859     PetscScalar dots[6];
8860 
8861     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
8862     for (j = 0; j < i; ++j) dots[j] *= -1.0;
8863     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
8864     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
8865   }
8866   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
8867   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
8868   PetscFunctionReturn(0);
8869 }
8870 
8871 #undef __FUNCT__
8872 #define __FUNCT__ "DMPlexGetHybridBounds"
8873 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
8874 {
8875   DM_Plex       *mesh = (DM_Plex*) dm->data;
8876   PetscInt       dim;
8877   PetscErrorCode ierr;
8878 
8879   PetscFunctionBegin;
8880   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8881   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8882   if (cMax) *cMax = mesh->hybridPointMax[dim];
8883   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
8884   if (eMax) *eMax = mesh->hybridPointMax[1];
8885   if (vMax) *vMax = mesh->hybridPointMax[0];
8886   PetscFunctionReturn(0);
8887 }
8888 
8889 #undef __FUNCT__
8890 #define __FUNCT__ "DMPlexSetHybridBounds"
8891 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
8892 {
8893   DM_Plex       *mesh = (DM_Plex*) dm->data;
8894   PetscInt       dim;
8895   PetscErrorCode ierr;
8896 
8897   PetscFunctionBegin;
8898   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8899   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8900   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
8901   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
8902   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
8903   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
8904   PetscFunctionReturn(0);
8905 }
8906 
8907 #undef __FUNCT__
8908 #define __FUNCT__ "DMPlexGetVTKCellHeight"
8909 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8910 {
8911   DM_Plex *mesh = (DM_Plex*) dm->data;
8912 
8913   PetscFunctionBegin;
8914   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8915   PetscValidPointer(cellHeight, 2);
8916   *cellHeight = mesh->vtkCellHeight;
8917   PetscFunctionReturn(0);
8918 }
8919 
8920 #undef __FUNCT__
8921 #define __FUNCT__ "DMPlexSetVTKCellHeight"
8922 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8923 {
8924   DM_Plex *mesh = (DM_Plex*) dm->data;
8925 
8926   PetscFunctionBegin;
8927   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8928   mesh->vtkCellHeight = cellHeight;
8929   PetscFunctionReturn(0);
8930 }
8931 
8932 #undef __FUNCT__
8933 #define __FUNCT__ "DMPlexCreateNumbering_Private"
8934 /* We can easily have a form that takes an IS instead */
8935 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
8936 {
8937   PetscSection   section, globalSection;
8938   PetscInt      *numbers, p;
8939   PetscErrorCode ierr;
8940 
8941   PetscFunctionBegin;
8942   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
8943   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
8944   for (p = pStart; p < pEnd; ++p) {
8945     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
8946   }
8947   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
8948   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8949   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
8950   for (p = pStart; p < pEnd; ++p) {
8951     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
8952   }
8953   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
8954   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
8955   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8956   PetscFunctionReturn(0);
8957 }
8958 
8959 #undef __FUNCT__
8960 #define __FUNCT__ "DMPlexGetCellNumbering"
8961 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8962 {
8963   DM_Plex       *mesh = (DM_Plex*) dm->data;
8964   PetscInt       cellHeight, cStart, cEnd, cMax;
8965   PetscErrorCode ierr;
8966 
8967   PetscFunctionBegin;
8968   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8969   if (!mesh->globalCellNumbers) {
8970     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8971     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8972     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
8973     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8974     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
8975   }
8976   *globalCellNumbers = mesh->globalCellNumbers;
8977   PetscFunctionReturn(0);
8978 }
8979 
8980 #undef __FUNCT__
8981 #define __FUNCT__ "DMPlexGetVertexNumbering"
8982 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8983 {
8984   DM_Plex       *mesh = (DM_Plex*) dm->data;
8985   PetscInt       vStart, vEnd, vMax;
8986   PetscErrorCode ierr;
8987 
8988   PetscFunctionBegin;
8989   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8990   if (!mesh->globalVertexNumbers) {
8991     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8992     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
8993     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
8994     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
8995   }
8996   *globalVertexNumbers = mesh->globalVertexNumbers;
8997   PetscFunctionReturn(0);
8998 }
8999 
9000 #undef __FUNCT__
9001 #define __FUNCT__ "DMPlexGetScale"
9002 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9003 {
9004   DM_Plex *mesh = (DM_Plex*) dm->data;
9005 
9006   PetscFunctionBegin;
9007   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9008   PetscValidPointer(scale, 3);
9009   *scale = mesh->scale[unit];
9010   PetscFunctionReturn(0);
9011 }
9012 
9013 #undef __FUNCT__
9014 #define __FUNCT__ "DMPlexSetScale"
9015 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9016 {
9017   DM_Plex *mesh = (DM_Plex*) dm->data;
9018 
9019   PetscFunctionBegin;
9020   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9021   mesh->scale[unit] = scale;
9022   PetscFunctionReturn(0);
9023 }
9024 
9025 
9026 /*******************************************************************************
9027 This should be in a separate Discretization object, but I am not sure how to lay
9028 it out yet, so I am stuffing things here while I experiment.
9029 *******************************************************************************/
9030 #undef __FUNCT__
9031 #define __FUNCT__ "DMPlexSetFEMIntegration"
9032 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9033                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9034                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9035                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9036                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9037                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9038                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9039                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9040                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9041                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9042                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9043                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9044                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9045                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9046                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9047                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9048                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9049 {
9050   DM_Plex *mesh = (DM_Plex*) dm->data;
9051 
9052   PetscFunctionBegin;
9053   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9054   mesh->integrateResidualFEM       = integrateResidualFEM;
9055   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9056   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9057   PetscFunctionReturn(0);
9058 }
9059 
9060 #undef __FUNCT__
9061 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9062 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9063 {
9064   Vec            coordinates;
9065   PetscSection   section, cSection;
9066   PetscInt       dim, vStart, vEnd, v, c, d;
9067   PetscScalar   *values, *cArray;
9068   PetscReal     *coords;
9069   PetscErrorCode ierr;
9070 
9071   PetscFunctionBegin;
9072   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9073   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9074   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9075   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9076   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9077   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9078   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9079   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9080   for (v = vStart; v < vEnd; ++v) {
9081     PetscInt dof, off;
9082 
9083     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9084     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9085     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9086     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9087     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9088     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9089   }
9090   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9091   /* Temporary, must be replaced by a projection on the finite element basis */
9092   {
9093     PetscInt eStart = 0, eEnd = 0, e, depth;
9094 
9095     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9096     --depth;
9097     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9098     for (e = eStart; e < eEnd; ++e) {
9099       const PetscInt *cone = NULL;
9100       PetscInt        coneSize, d;
9101       PetscScalar    *coordsA, *coordsB;
9102 
9103       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9104       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9105       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9106       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9107       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9108       for (d = 0; d < dim; ++d) {
9109         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9110       }
9111       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9112       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9113     }
9114   }
9115 
9116   ierr = PetscFree(coords);CHKERRQ(ierr);
9117   ierr = PetscFree(values);CHKERRQ(ierr);
9118 #if 0
9119   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9120   PetscReal      detJ;
9121 
9122   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9123   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9124   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9125 
9126   for (PetscInt c = cStart; c < cEnd; ++c) {
9127     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9128     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9129     const int                          oSize   = pV.getSize();
9130     int                                v       = 0;
9131 
9132     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9133     for (PetscInt cl = 0; cl < oSize; ++cl) {
9134       const PetscInt fDim;
9135 
9136       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9137       if (pointDim) {
9138         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9139           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9140         }
9141       }
9142     }
9143     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9144     pV.clear();
9145   }
9146   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9147   ierr = PetscFree(values);CHKERRQ(ierr);
9148 #endif
9149   PetscFunctionReturn(0);
9150 }
9151 
9152 #undef __FUNCT__
9153 #define __FUNCT__ "DMPlexProjectFunction"
9154 /*@C
9155   DMPlexProjectFunction - This projects the given function into the function space provided.
9156 
9157   Input Parameters:
9158 + dm      - The DM
9159 . numComp - The number of components (functions)
9160 . funcs   - The coordinate functions to evaluate
9161 - mode    - The insertion mode for values
9162 
9163   Output Parameter:
9164 . X - vector
9165 
9166   Level: developer
9167 
9168   Note:
9169   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9170   We will eventually fix it.
9171 
9172 ,seealso: DMPlexComputeL2Diff()
9173 */
9174 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9175 {
9176   Vec            localX;
9177   PetscErrorCode ierr;
9178 
9179   PetscFunctionBegin;
9180   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9181   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9182   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9183   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9184   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9185   PetscFunctionReturn(0);
9186 }
9187 
9188 #undef __FUNCT__
9189 #define __FUNCT__ "DMPlexComputeL2Diff"
9190 /*@C
9191   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9192 
9193   Input Parameters:
9194 + dm    - The DM
9195 . quad  - The PetscQuadrature object for each field
9196 . funcs - The functions to evaluate for each field component
9197 - X     - The coefficient vector u_h
9198 
9199   Output Parameter:
9200 . diff - The diff ||u - u_h||_2
9201 
9202   Level: developer
9203 
9204 .seealso: DMPlexProjectFunction()
9205 */
9206 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9207 {
9208   const PetscInt debug = 0;
9209   PetscSection   section;
9210   Vec            localX;
9211   PetscReal     *coords, *v0, *J, *invJ, detJ;
9212   PetscReal      localDiff = 0.0;
9213   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9214   PetscErrorCode ierr;
9215 
9216   PetscFunctionBegin;
9217   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9218   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9219   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9220   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9221   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9222   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9223   for (field = 0; field < numFields; ++field) {
9224     numComponents += quad[field].numComponents;
9225   }
9226   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9227   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9228   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9229   for (c = cStart; c < cEnd; ++c) {
9230     const PetscScalar *x;
9231     PetscReal          elemDiff = 0.0;
9232 
9233     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9234     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9235     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9236 
9237     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9238       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9239       const PetscReal *quadPoints    = quad[field].quadPoints;
9240       const PetscReal *quadWeights   = quad[field].quadWeights;
9241       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9242       const PetscInt   numBasisComps = quad[field].numComponents;
9243       const PetscReal *basis         = quad[field].basis;
9244       PetscInt         q, d, e, fc, f;
9245 
9246       if (debug) {
9247         char title[1024];
9248         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9249         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9250       }
9251       for (q = 0; q < numQuadPoints; ++q) {
9252         for (d = 0; d < dim; d++) {
9253           coords[d] = v0[d];
9254           for (e = 0; e < dim; e++) {
9255             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9256           }
9257         }
9258         for (fc = 0; fc < numBasisComps; ++fc) {
9259           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9260           PetscReal       interpolant = 0.0;
9261           for (f = 0; f < numBasisFuncs; ++f) {
9262             const PetscInt fidx = f*numBasisComps+fc;
9263             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9264           }
9265           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9266           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9267         }
9268       }
9269       comp        += numBasisComps;
9270       fieldOffset += numBasisFuncs*numBasisComps;
9271     }
9272     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9273     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9274     localDiff += elemDiff;
9275   }
9276   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9277   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9278   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9279   *diff = PetscSqrtReal(*diff);
9280   PetscFunctionReturn(0);
9281 }
9282 
9283 #undef __FUNCT__
9284 #define __FUNCT__ "DMPlexComputeResidualFEM"
9285 /*@
9286   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9287 
9288   Input Parameters:
9289 + dm - The mesh
9290 . X  - Local input vector
9291 - user - The user context
9292 
9293   Output Parameter:
9294 . F  - Local output vector
9295 
9296   Note:
9297   The second member of the user context must be an FEMContext.
9298 
9299   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9300   like a GPU, or vectorize on a multicore machine.
9301 
9302 .seealso: DMPlexComputeJacobianActionFEM()
9303 */
9304 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9305 {
9306   DM_Plex         *mesh = (DM_Plex*) dm->data;
9307   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9308   PetscQuadrature *quad = fem->quad;
9309   PetscSection     section;
9310   PetscReal       *v0, *J, *invJ, *detJ;
9311   PetscScalar     *elemVec, *u;
9312   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9313   PetscInt         cellDof = 0, numComponents = 0;
9314   PetscErrorCode   ierr;
9315 
9316   PetscFunctionBegin;
9317   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9318   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9319   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9320   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9321   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9322   numCells = cEnd - cStart;
9323   for (field = 0; field < numFields; ++field) {
9324     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9325     numComponents += quad[field].numComponents;
9326   }
9327   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9328   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9329   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
9330   for (c = cStart; c < cEnd; ++c) {
9331     const PetscScalar *x;
9332     PetscInt           i;
9333 
9334     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9335     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9336     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9337 
9338     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9339     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9340   }
9341   for (field = 0; field < numFields; ++field) {
9342     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9343     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9344     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9345     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9346     /* Conforming batches */
9347     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9348     PetscInt numBlocks  = 1;
9349     PetscInt batchSize  = numBlocks * blockSize;
9350     PetscInt numBatches = numBatchesTmp;
9351     PetscInt numChunks  = numCells / (numBatches*batchSize);
9352     /* Remainder */
9353     PetscInt numRemainder = numCells % (numBatches * batchSize);
9354     PetscInt offset       = numCells - numRemainder;
9355 
9356     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9357     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9358                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9359   }
9360   for (c = cStart; c < cEnd; ++c) {
9361     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9362     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9363   }
9364   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9365   if (mesh->printFEM) {
9366     PetscMPIInt rank, numProcs;
9367     PetscInt    p;
9368 
9369     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9370     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9371     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9372     for (p = 0; p < numProcs; ++p) {
9373       if (p == rank) {
9374         Vec f;
9375 
9376         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9377         ierr = VecCopy(F, f);CHKERRQ(ierr);
9378         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9379         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9380         ierr = VecDestroy(&f);CHKERRQ(ierr);
9381         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9382       }
9383       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9384     }
9385   }
9386   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9387   PetscFunctionReturn(0);
9388 }
9389 
9390 #undef __FUNCT__
9391 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9392 /*@C
9393   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9394 
9395   Input Parameters:
9396 + dm - The mesh
9397 . J  - The Jacobian shell matrix
9398 . X  - Local input vector
9399 - user - The user context
9400 
9401   Output Parameter:
9402 . F  - Local output vector
9403 
9404   Note:
9405   The second member of the user context must be an FEMContext.
9406 
9407   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9408   like a GPU, or vectorize on a multicore machine.
9409 
9410 .seealso: DMPlexComputeResidualFEM()
9411 */
9412 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9413 {
9414   DM_Plex         *mesh = (DM_Plex*) dm->data;
9415   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9416   PetscQuadrature *quad = fem->quad;
9417   PetscSection     section;
9418   JacActionCtx    *jctx;
9419   PetscReal       *v0, *J, *invJ, *detJ;
9420   PetscScalar     *elemVec, *u, *a;
9421   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9422   PetscInt         cellDof = 0;
9423   PetscErrorCode   ierr;
9424 
9425   PetscFunctionBegin;
9426   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9427   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9428   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9429   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9430   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9431   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9432   numCells = cEnd - cStart;
9433   for (field = 0; field < numFields; ++field) {
9434     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9435   }
9436   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9437   ierr = PetscMalloc7(numCells*cellDof,PetscScalar,&u,numCells*cellDof,PetscScalar,&a,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
9438   for (c = cStart; c < cEnd; ++c) {
9439     const PetscScalar *x;
9440     PetscInt           i;
9441 
9442     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9443     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9444     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9445     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9446     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9447     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9448     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9449     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9450   }
9451   for (field = 0; field < numFields; ++field) {
9452     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9453     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9454     /* Conforming batches */
9455     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9456     PetscInt numBlocks  = 1;
9457     PetscInt batchSize  = numBlocks * blockSize;
9458     PetscInt numBatches = numBatchesTmp;
9459     PetscInt numChunks  = numCells / (numBatches*batchSize);
9460     /* Remainder */
9461     PetscInt numRemainder = numCells % (numBatches * batchSize);
9462     PetscInt offset       = numCells - numRemainder;
9463 
9464     ierr = (*mesh->integrateJacobianActionFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, a, v0, J, invJ, detJ, fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, elemVec);CHKERRQ(ierr);
9465     ierr = (*mesh->integrateJacobianActionFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &a[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9466                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9467   }
9468   for (c = cStart; c < cEnd; ++c) {
9469     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9470     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9471   }
9472   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9473   if (mesh->printFEM) {
9474     PetscMPIInt rank, numProcs;
9475     PetscInt    p;
9476 
9477     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9478     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9479     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9480     for (p = 0; p < numProcs; ++p) {
9481       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9482       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9483     }
9484   }
9485   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9486   PetscFunctionReturn(0);
9487 }
9488 
9489 #undef __FUNCT__
9490 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9491 /*@
9492   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9493 
9494   Input Parameters:
9495 + dm - The mesh
9496 . X  - Local input vector
9497 - user - The user context
9498 
9499   Output Parameter:
9500 . Jac  - Jacobian matrix
9501 
9502   Note:
9503   The second member of the user context must be an FEMContext.
9504 
9505   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9506   like a GPU, or vectorize on a multicore machine.
9507 
9508 .seealso: FormFunctionLocal()
9509 */
9510 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9511 {
9512   DM_Plex         *mesh = (DM_Plex*) dm->data;
9513   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9514   PetscQuadrature *quad = fem->quad;
9515   PetscSection     section;
9516   PetscReal       *v0, *J, *invJ, *detJ;
9517   PetscScalar     *elemMat, *u;
9518   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9519   PetscInt         cellDof = 0, numComponents = 0;
9520   PetscBool        isShell;
9521   PetscErrorCode   ierr;
9522 
9523   PetscFunctionBegin;
9524   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9525   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9526   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9527   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9528   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9529   numCells = cEnd - cStart;
9530   for (field = 0; field < numFields; ++field) {
9531     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9532     numComponents += quad[field].numComponents;
9533   }
9534   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9535   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9536   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof*cellDof,PetscScalar,&elemMat);CHKERRQ(ierr);
9537   for (c = cStart; c < cEnd; ++c) {
9538     const PetscScalar *x;
9539     PetscInt           i;
9540 
9541     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9542     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9543     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9544 
9545     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9546     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9547   }
9548   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9549   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9550     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9551     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9552     PetscInt       fieldJ;
9553 
9554     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9555       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9556       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9557       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9558       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9559       /* Conforming batches */
9560       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9561       PetscInt numBlocks  = 1;
9562       PetscInt batchSize  = numBlocks * blockSize;
9563       PetscInt numBatches = numBatchesTmp;
9564       PetscInt numChunks  = numCells / (numBatches*batchSize);
9565       /* Remainder */
9566       PetscInt numRemainder = numCells % (numBatches * batchSize);
9567       PetscInt offset       = numCells - numRemainder;
9568 
9569       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9570       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9571                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9572     }
9573   }
9574   for (c = cStart; c < cEnd; ++c) {
9575     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9576     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9577   }
9578   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9579 
9580   /* Assemble matrix, using the 2-step process:
9581        MatAssemblyBegin(), MatAssemblyEnd(). */
9582   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9583   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9584 
9585   if (mesh->printFEM) {
9586     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9587     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9588     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9589   }
9590   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9591   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9592   if (isShell) {
9593     JacActionCtx *jctx;
9594 
9595     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9596     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9597   }
9598   *str = SAME_NONZERO_PATTERN;
9599   PetscFunctionReturn(0);
9600 }
9601 
9602 
9603 #undef __FUNCT__
9604 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9605 /*@C
9606   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9607   the local section and an SF describing the section point overlap.
9608 
9609   Input Parameters:
9610   + s - The PetscSection for the local field layout
9611   . sf - The SF describing parallel layout of the section points
9612   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9613   . label - The label specifying the points
9614   - labelValue - The label stratum specifying the points
9615 
9616   Output Parameter:
9617   . gsection - The PetscSection for the global field layout
9618 
9619   Note: This gives negative sizes and offsets to points not owned by this process
9620 
9621   Level: developer
9622 
9623 .seealso: PetscSectionCreate()
9624 @*/
9625 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9626 {
9627   PetscInt      *neg;
9628   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9629   PetscErrorCode ierr;
9630 
9631   PetscFunctionBegin;
9632   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9633   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9634   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9635   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9636   /* Mark ghost points with negative dof */
9637   for (p = pStart; p < pEnd; ++p) {
9638     PetscInt value;
9639 
9640     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9641     if (value != labelValue) continue;
9642     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9643     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9644     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9645     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9646     neg[p-pStart] = -(dof+1);
9647   }
9648   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9649   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
9650   if (nroots >= 0) {
9651     if (nroots > pEnd - pStart) {
9652       PetscInt *tmpDof;
9653       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9654       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9655       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9656       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9657       for (p = pStart; p < pEnd; ++p) {
9658         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
9659       }
9660       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9661     } else {
9662       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9663       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9664     }
9665   }
9666   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9667   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9668     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9669 
9670     (*gsection)->atlasOff[p] = off;
9671 
9672     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9673   }
9674   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9675   globalOff -= off;
9676   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9677     (*gsection)->atlasOff[p] += globalOff;
9678 
9679     neg[p] = -((*gsection)->atlasOff[p]+1);
9680   }
9681   /* Put in negative offsets for ghost points */
9682   if (nroots >= 0) {
9683     if (nroots > pEnd - pStart) {
9684       PetscInt *tmpOff;
9685       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9686       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9687       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9688       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9689       for (p = pStart; p < pEnd; ++p) {
9690         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
9691       }
9692       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9693     } else {
9694       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9695       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9696     }
9697   }
9698   ierr = PetscFree(neg);CHKERRQ(ierr);
9699   PetscFunctionReturn(0);
9700 }
9701