xref: /petsc/src/dm/impls/plex/plex.c (revision 85ec1a3c60f730c6f15bb17d503400c92ac73e43)
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_2D"
3743 PetscErrorCode DMPlexConstructGhostCells_2D(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 (this could be auto-generated)
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   switch (dim) {
3862   case 2:
3863     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3864     break;
3865   default:
3866     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3867   }
3868   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3869   *dmGhosted = gdm;
3870   PetscFunctionReturn(0);
3871 }
3872 
3873 #undef __FUNCT__
3874 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3875 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3876 {
3877   MPI_Comm        comm;
3878   IS              valueIS, *pointIS;
3879   const PetscInt *values, **splitPoints;
3880   PetscSection    coordSection;
3881   Vec             coordinates;
3882   PetscScalar    *coords;
3883   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3884   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3885   PetscErrorCode  ierr;
3886 
3887   PetscFunctionBegin;
3888   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3889   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3890   /* Count split points and add cohesive cells */
3891   if (label) {
3892     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3893     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3894     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3895   }
3896   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3897   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3898   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3899   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3900   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3901   for (d = 0; d <= depth; ++d) {
3902     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3903     numSplitPoints[d] = 0;
3904     splitPoints[d]    = NULL;
3905     pointIS[d]        = NULL;
3906   }
3907   for (sp = 0; sp < numSP; ++sp) {
3908     const PetscInt dep = values[sp];
3909 
3910     if ((dep < 0) || (dep > depth)) continue;
3911     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3912     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3913     if (pointIS[dep]) {
3914       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3915       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3916     }
3917   }
3918   if (depth >= 0) {
3919     /* Calculate number of additional points */
3920     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3921     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3922     /* Calculate hybrid bound for each dimension */
3923     pMaxNew[0] += depthShift[depth];
3924     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3925     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3926 
3927     /* Calculate point offset for each dimension */
3928     depthOffset[depth] = 0;
3929     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3930     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3931     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3932   }
3933   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3934   /* Step 3: Set cone/support sizes for new points */
3935   for (dep = 0; dep <= depth; ++dep) {
3936     for (p = 0; p < numSplitPoints[dep]; ++p) {
3937       const PetscInt  oldp   = splitPoints[dep][p];
3938       const PetscInt  newp   = depthOffset[dep] + oldp;
3939       const PetscInt  splitp = pMaxNew[dep] + p;
3940       const PetscInt *support;
3941       PetscInt        coneSize, supportSize, q, e;
3942 
3943       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3944       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3945       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3946       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3947       if (dep == depth-1) {
3948         const PetscInt ccell = pMaxNew[depth] + p;
3949         /* Add cohesive cells, they are prisms */
3950         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3951       } else if (dep == 0) {
3952         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3953 
3954         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3955         /* Split old vertex: Edges in old split faces and new cohesive edge */
3956         for (e = 0, q = 0; e < supportSize; ++e) {
3957           PetscInt val;
3958 
3959           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3960           if ((val == 1) || (val == (shift + 1))) ++q;
3961         }
3962         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3963         /* Split new vertex: Edges in new split faces and new cohesive edge */
3964         for (e = 0, q = 0; e < supportSize; ++e) {
3965           PetscInt val;
3966 
3967           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3968           if ((val == 1) || (val == -(shift + 1))) ++q;
3969         }
3970         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
3971         /* Add cohesive edges */
3972         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
3973         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3974       } else if (dep == dim-2) {
3975         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3976         /* Split old edge: Faces in positive side cells and old split faces */
3977         for (e = 0, q = 0; e < supportSize; ++e) {
3978           PetscInt val;
3979 
3980           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3981           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
3982         }
3983         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
3984         /* Split new edge: Faces in negative side cells and new split faces */
3985         for (e = 0, q = 0; e < supportSize; ++e) {
3986           PetscInt val;
3987 
3988           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3989           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
3990         }
3991         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
3992       }
3993     }
3994   }
3995   /* Step 4: Setup split DM */
3996   ierr = DMSetUp(sdm);CHKERRQ(ierr);
3997   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3998   /* Step 6: Set cones and supports for new points */
3999   for (dep = 0; dep <= depth; ++dep) {
4000     for (p = 0; p < numSplitPoints[dep]; ++p) {
4001       const PetscInt  oldp   = splitPoints[dep][p];
4002       const PetscInt  newp   = depthOffset[dep] + oldp;
4003       const PetscInt  splitp = pMaxNew[dep] + p;
4004       const PetscInt *cone, *support, *ornt;
4005       PetscInt        coneSize, supportSize, q, v, e, s;
4006 
4007       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4008       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4009       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4010       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4011       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4012       if (dep == depth-1) {
4013         const PetscInt  ccell = pMaxNew[depth] + p;
4014         const PetscInt *supportF;
4015 
4016         /* Split face:       copy in old face to new face to start */
4017         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4018         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4019         /* Split old face:   old vertices/edges in cone so no change */
4020         /* Split new face:   new vertices/edges in cone */
4021         for (q = 0; q < coneSize; ++q) {
4022           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4023 
4024           coneNew[2+q] = pMaxNew[dim-2] + v;
4025         }
4026         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4027         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4028         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4029         coneNew[0] = newp;
4030         coneNew[1] = splitp;
4031         for (q = 0; q < coneSize; ++q) {
4032           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4033         }
4034         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4035 
4036 
4037         for (s = 0; s < supportSize; ++s) {
4038           PetscInt val;
4039 
4040           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4041           if (val < 0) {
4042             /* Split old face:   Replace negative side cell with cohesive cell */
4043             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4044           } else {
4045             /* Split new face:   Replace positive side cell with cohesive cell */
4046             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4047           }
4048         }
4049       } else if (dep == 0) {
4050         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4051 
4052         /* Split old vertex: Edges in old split faces and new cohesive edge */
4053         for (e = 0, q = 0; e < supportSize; ++e) {
4054           PetscInt val;
4055 
4056           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4057           if ((val == 1) || (val == (shift + 1))) {
4058             supportNew[q++] = depthOffset[1] + support[e];
4059           }
4060         }
4061         supportNew[q] = cedge;
4062 
4063         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4064         /* Split new vertex: Edges in new split faces and new cohesive edge */
4065         for (e = 0, q = 0; e < supportSize; ++e) {
4066           PetscInt val, edge;
4067 
4068           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4069           if (val == 1) {
4070             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4071             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4072             supportNew[q++] = pMaxNew[1] + edge;
4073           } else if (val == -(shift + 1)) {
4074             supportNew[q++] = depthOffset[1] + support[e];
4075           }
4076         }
4077         supportNew[q] = cedge;
4078         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4079         /* Cohesive edge:    Old and new split vertex, punting on support */
4080         coneNew[0] = newp;
4081         coneNew[1] = splitp;
4082         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4083       } else if (dep == dim-2) {
4084         /* Split old edge:   old vertices in cone so no change */
4085         /* Split new edge:   new vertices in cone */
4086         for (q = 0; q < coneSize; ++q) {
4087           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4088 
4089           coneNew[q] = pMaxNew[dim-3] + v;
4090         }
4091         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4092         /* Split old edge: Faces in positive side cells and old split faces */
4093         for (e = 0, q = 0; e < supportSize; ++e) {
4094           PetscInt val;
4095 
4096           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4097           if ((val == dim-1) || (val == (shift + dim-1))) {
4098             supportNew[q++] = depthOffset[dim-1] + support[e];
4099           }
4100         }
4101         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4102         /* Split new edge: Faces in negative side cells and new split faces */
4103         for (e = 0, q = 0; e < supportSize; ++e) {
4104           PetscInt val, face;
4105 
4106           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4107           if (val == dim-1) {
4108             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4109             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4110             supportNew[q++] = pMaxNew[dim-1] + face;
4111           } else if (val == -(shift + dim-1)) {
4112             supportNew[q++] = depthOffset[dim-1] + support[e];
4113           }
4114         }
4115         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4116       }
4117     }
4118   }
4119   /* Step 6b: Replace split points in negative side cones */
4120   for (sp = 0; sp < numSP; ++sp) {
4121     PetscInt        dep = values[sp];
4122     IS              pIS;
4123     PetscInt        numPoints;
4124     const PetscInt *points;
4125 
4126     if (dep >= 0) continue;
4127     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4128     if (!pIS) continue;
4129     dep  = -dep - shift;
4130     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4131     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4132     for (p = 0; p < numPoints; ++p) {
4133       const PetscInt  oldp = points[p];
4134       const PetscInt  newp = depthOffset[dep] + oldp;
4135       const PetscInt *cone;
4136       PetscInt        coneSize, c;
4137       PetscBool       replaced = PETSC_FALSE;
4138 
4139       /* Negative edge: replace split vertex */
4140       /* Negative cell: replace split face */
4141       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4142       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4143       for (c = 0; c < coneSize; ++c) {
4144         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4145         PetscInt       csplitp, cp, val;
4146 
4147         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4148         if (val == dep-1) {
4149           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4150           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4151           csplitp  = pMaxNew[dep-1] + cp;
4152           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4153           replaced = PETSC_TRUE;
4154         }
4155       }
4156       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4157     }
4158     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4159     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4160   }
4161   /* Step 7: Stratify */
4162   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4163   /* Step 8: Coordinates */
4164   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4165   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4166   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4167   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4168   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4169     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4170     const PetscInt splitp = pMaxNew[0] + v;
4171     PetscInt       dof, off, soff, d;
4172 
4173     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4174     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4175     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4176     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4177   }
4178   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4179   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4180   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4181   /* Step 10: Labels */
4182   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4183   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4184   for (dep = 0; dep <= depth; ++dep) {
4185     for (p = 0; p < numSplitPoints[dep]; ++p) {
4186       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4187       const PetscInt splitp = pMaxNew[dep] + p;
4188       PetscInt       l;
4189 
4190       for (l = 0; l < numLabels; ++l) {
4191         DMLabel     mlabel;
4192         const char *lname;
4193         PetscInt    val;
4194 
4195         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4196         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4197         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4198         if (val >= 0) {
4199           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4200           if (dep == 0) {
4201             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4202             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4203           }
4204         }
4205       }
4206     }
4207   }
4208   for (sp = 0; sp < numSP; ++sp) {
4209     const PetscInt dep = values[sp];
4210 
4211     if ((dep < 0) || (dep > depth)) continue;
4212     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4213     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4214   }
4215   if (label) {
4216     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4217     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4218   }
4219   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4220   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4221   PetscFunctionReturn(0);
4222 }
4223 
4224 #undef __FUNCT__
4225 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4226 /*@C
4227   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4228 
4229   Collective on dm
4230 
4231   Input Parameters:
4232 + dm - The original DM
4233 - labelName - The label specifying the boundary faces (this could be auto-generated)
4234 
4235   Output Parameters:
4236 - dmSplit - The new DM
4237 
4238   Level: developer
4239 
4240 .seealso: DMCreate()
4241 */
4242 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4243 {
4244   DM             sdm;
4245   PetscInt       dim;
4246   PetscErrorCode ierr;
4247 
4248   PetscFunctionBegin;
4249   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4250   PetscValidPointer(dmSplit, 4);
4251   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &sdm);CHKERRQ(ierr);
4252   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4253   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4254   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4255   switch (dim) {
4256   case 2:
4257   case 3:
4258     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4259     break;
4260   default:
4261     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4262   }
4263   *dmSplit = sdm;
4264   PetscFunctionReturn(0);
4265 }
4266 
4267 #undef __FUNCT__
4268 #define __FUNCT__ "DMLabelCohesiveComplete"
4269 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4270 {
4271   IS              dimIS;
4272   const PetscInt *points;
4273   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4274   PetscErrorCode  ierr;
4275 
4276   PetscFunctionBegin;
4277   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4278   /* Cell orientation for face gives the side of the fault */
4279   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4280   if (!dimIS) PetscFunctionReturn(0);
4281   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4282   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4283   for (p = 0; p < numPoints; ++p) {
4284     const PetscInt *support;
4285     PetscInt        supportSize, s;
4286 
4287     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4288     if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4289     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4290     for (s = 0; s < supportSize; ++s) {
4291       const PetscInt *cone, *ornt;
4292       PetscInt        coneSize, c;
4293       PetscBool       pos = PETSC_TRUE;
4294 
4295       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4296       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4297       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4298       for (c = 0; c < coneSize; ++c) {
4299         if (cone[c] == points[p]) {
4300           if (ornt[c] >= 0) {
4301             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4302           } else {
4303             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4304             pos  = PETSC_FALSE;
4305           }
4306           break;
4307         }
4308       }
4309       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]);
4310       /* Put faces touching the fault in the label */
4311       for (c = 0; c < coneSize; ++c) {
4312         const PetscInt point = cone[c];
4313 
4314         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4315         if (val == -1) {
4316           PetscInt *closure = NULL;
4317           PetscInt  closureSize, cl;
4318 
4319           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4320           for (cl = 0; cl < closureSize*2; cl += 2) {
4321             const PetscInt clp = closure[cl];
4322 
4323             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4324             if ((val >= 0) && (val < dim-1)) {
4325               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4326               break;
4327             }
4328           }
4329           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4330         }
4331       }
4332     }
4333   }
4334   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4335   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4336   /* Search for other cells/faces/edges connected to the fault by a vertex */
4337   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4338   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4339   if (!dimIS) PetscFunctionReturn(0);
4340   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4341   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4342   for (p = 0; p < numPoints; ++p) {
4343     PetscInt *star = NULL;
4344     PetscInt  starSize, s;
4345     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4346 
4347     /* First mark cells connected to the fault */
4348     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4349     while (again) {
4350       if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4351       again = 0;
4352       for (s = 0; s < starSize*2; s += 2) {
4353         const PetscInt  point = star[s];
4354         const PetscInt *cone;
4355         PetscInt        coneSize, c;
4356 
4357         if ((point < cStart) || (point >= cEnd)) continue;
4358         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4359         if (val != -1) continue;
4360         again = 2;
4361         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4362         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4363         for (c = 0; c < coneSize; ++c) {
4364           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4365           if (val != -1) {
4366             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);
4367             if (val > 0) {
4368               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4369             } else {
4370               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4371             }
4372             again = 1;
4373             break;
4374           }
4375         }
4376       }
4377     }
4378     /* Classify the rest by cell membership */
4379     for (s = 0; s < starSize*2; s += 2) {
4380       const PetscInt point = star[s];
4381 
4382       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4383       if (val == -1) {
4384         PetscInt  *sstar = NULL;
4385         PetscInt   sstarSize, ss;
4386         PetscBool  marked = PETSC_FALSE;
4387 
4388         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4389         for (ss = 0; ss < sstarSize*2; ss += 2) {
4390           const PetscInt spoint = sstar[ss];
4391 
4392           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4393           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4394           if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4395           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4396           if (val > 0) {
4397             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4398           } else {
4399             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4400           }
4401           marked = PETSC_TRUE;
4402           break;
4403         }
4404         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4405         if (!marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
4406       }
4407     }
4408     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4409   }
4410   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4411   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4412   PetscFunctionReturn(0);
4413 }
4414 
4415 #if defined(PETSC_HAVE_TRIANGLE)
4416 #include <triangle.h>
4417 
4418 #undef __FUNCT__
4419 #define __FUNCT__ "InitInput_Triangle"
4420 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4421 {
4422   PetscFunctionBegin;
4423   inputCtx->numberofpoints             = 0;
4424   inputCtx->numberofpointattributes    = 0;
4425   inputCtx->pointlist                  = NULL;
4426   inputCtx->pointattributelist         = NULL;
4427   inputCtx->pointmarkerlist            = NULL;
4428   inputCtx->numberofsegments           = 0;
4429   inputCtx->segmentlist                = NULL;
4430   inputCtx->segmentmarkerlist          = NULL;
4431   inputCtx->numberoftriangleattributes = 0;
4432   inputCtx->trianglelist               = NULL;
4433   inputCtx->numberofholes              = 0;
4434   inputCtx->holelist                   = NULL;
4435   inputCtx->numberofregions            = 0;
4436   inputCtx->regionlist                 = NULL;
4437   PetscFunctionReturn(0);
4438 }
4439 
4440 #undef __FUNCT__
4441 #define __FUNCT__ "InitOutput_Triangle"
4442 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4443 {
4444   PetscFunctionBegin;
4445   outputCtx->numberofpoints        = 0;
4446   outputCtx->pointlist             = NULL;
4447   outputCtx->pointattributelist    = NULL;
4448   outputCtx->pointmarkerlist       = NULL;
4449   outputCtx->numberoftriangles     = 0;
4450   outputCtx->trianglelist          = NULL;
4451   outputCtx->triangleattributelist = NULL;
4452   outputCtx->neighborlist          = NULL;
4453   outputCtx->segmentlist           = NULL;
4454   outputCtx->segmentmarkerlist     = NULL;
4455   outputCtx->numberofedges         = 0;
4456   outputCtx->edgelist              = NULL;
4457   outputCtx->edgemarkerlist        = NULL;
4458   PetscFunctionReturn(0);
4459 }
4460 
4461 #undef __FUNCT__
4462 #define __FUNCT__ "FiniOutput_Triangle"
4463 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4464 {
4465   PetscFunctionBegin;
4466   free(outputCtx->pointmarkerlist);
4467   free(outputCtx->edgelist);
4468   free(outputCtx->edgemarkerlist);
4469   free(outputCtx->trianglelist);
4470   free(outputCtx->neighborlist);
4471   PetscFunctionReturn(0);
4472 }
4473 
4474 #undef __FUNCT__
4475 #define __FUNCT__ "DMPlexGenerate_Triangle"
4476 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4477 {
4478   MPI_Comm             comm;
4479   PetscInt             dim              = 2;
4480   const PetscBool      createConvexHull = PETSC_FALSE;
4481   const PetscBool      constrained      = PETSC_FALSE;
4482   struct triangulateio in;
4483   struct triangulateio out;
4484   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4485   PetscMPIInt          rank;
4486   PetscErrorCode       ierr;
4487 
4488   PetscFunctionBegin;
4489   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4490   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4491   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4492   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4493   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4494 
4495   in.numberofpoints = vEnd - vStart;
4496   if (in.numberofpoints > 0) {
4497     PetscSection coordSection;
4498     Vec          coordinates;
4499     PetscScalar *array;
4500 
4501     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4502     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4503     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4504     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4505     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4506     for (v = vStart; v < vEnd; ++v) {
4507       const PetscInt idx = v - vStart;
4508       PetscInt       off, d;
4509 
4510       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4511       for (d = 0; d < dim; ++d) {
4512         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4513       }
4514       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4515     }
4516     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4517   }
4518   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4519   in.numberofsegments = eEnd - eStart;
4520   if (in.numberofsegments > 0) {
4521     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4522     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4523     for (e = eStart; e < eEnd; ++e) {
4524       const PetscInt  idx = e - eStart;
4525       const PetscInt *cone;
4526 
4527       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4528 
4529       in.segmentlist[idx*2+0] = cone[0] - vStart;
4530       in.segmentlist[idx*2+1] = cone[1] - vStart;
4531 
4532       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4533     }
4534   }
4535 #if 0 /* Do not currently support holes */
4536   PetscReal *holeCoords;
4537   PetscInt   h, d;
4538 
4539   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4540   if (in.numberofholes > 0) {
4541     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4542     for (h = 0; h < in.numberofholes; ++h) {
4543       for (d = 0; d < dim; ++d) {
4544         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4545       }
4546     }
4547   }
4548 #endif
4549   if (!rank) {
4550     char args[32];
4551 
4552     /* Take away 'Q' for verbose output */
4553     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4554     if (createConvexHull) {
4555       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4556     }
4557     if (constrained) {
4558       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4559     }
4560     triangulate(args, &in, &out, NULL);
4561   }
4562   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4563   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4564   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4565   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4566   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4567 
4568   {
4569     const PetscInt numCorners  = 3;
4570     const PetscInt numCells    = out.numberoftriangles;
4571     const PetscInt numVertices = out.numberofpoints;
4572     const int     *cells      = out.trianglelist;
4573     const double  *meshCoords = out.pointlist;
4574 
4575     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4576     /* Set labels */
4577     for (v = 0; v < numVertices; ++v) {
4578       if (out.pointmarkerlist[v]) {
4579         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4580       }
4581     }
4582     if (interpolate) {
4583       for (e = 0; e < out.numberofedges; e++) {
4584         if (out.edgemarkerlist[e]) {
4585           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4586           const PetscInt *edges;
4587           PetscInt        numEdges;
4588 
4589           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4590           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4591           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4592           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4593         }
4594       }
4595     }
4596     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4597   }
4598 #if 0 /* Do not currently support holes */
4599   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4600 #endif
4601   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4602   PetscFunctionReturn(0);
4603 }
4604 
4605 #undef __FUNCT__
4606 #define __FUNCT__ "DMPlexRefine_Triangle"
4607 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4608 {
4609   MPI_Comm             comm;
4610   PetscInt             dim  = 2;
4611   struct triangulateio in;
4612   struct triangulateio out;
4613   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4614   PetscMPIInt          rank;
4615   PetscErrorCode       ierr;
4616 
4617   PetscFunctionBegin;
4618   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4619   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4620   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4621   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4622   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4623   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4624   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4625 
4626   in.numberofpoints = vEnd - vStart;
4627   if (in.numberofpoints > 0) {
4628     PetscSection coordSection;
4629     Vec          coordinates;
4630     PetscScalar *array;
4631 
4632     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4633     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4634     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4635     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4636     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4637     for (v = vStart; v < vEnd; ++v) {
4638       const PetscInt idx = v - vStart;
4639       PetscInt       off, d;
4640 
4641       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4642       for (d = 0; d < dim; ++d) {
4643         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4644       }
4645       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4646     }
4647     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4648   }
4649   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4650 
4651   in.numberofcorners   = 3;
4652   in.numberoftriangles = cEnd - cStart;
4653 
4654   in.trianglearealist  = (double*) maxVolumes;
4655   if (in.numberoftriangles > 0) {
4656     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4657     for (c = cStart; c < cEnd; ++c) {
4658       const PetscInt idx      = c - cStart;
4659       PetscInt      *closure = NULL;
4660       PetscInt       closureSize;
4661 
4662       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4663       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4664       for (v = 0; v < 3; ++v) {
4665         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4666       }
4667       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4668     }
4669   }
4670   /* TODO: Segment markers are missing on input */
4671 #if 0 /* Do not currently support holes */
4672   PetscReal *holeCoords;
4673   PetscInt   h, d;
4674 
4675   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4676   if (in.numberofholes > 0) {
4677     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4678     for (h = 0; h < in.numberofholes; ++h) {
4679       for (d = 0; d < dim; ++d) {
4680         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4681       }
4682     }
4683   }
4684 #endif
4685   if (!rank) {
4686     char args[32];
4687 
4688     /* Take away 'Q' for verbose output */
4689     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4690     triangulate(args, &in, &out, NULL);
4691   }
4692   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4693   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4694   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4695   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4696   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4697 
4698   {
4699     const PetscInt numCorners  = 3;
4700     const PetscInt numCells    = out.numberoftriangles;
4701     const PetscInt numVertices = out.numberofpoints;
4702     const int     *cells      = out.trianglelist;
4703     const double  *meshCoords = out.pointlist;
4704     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4705 
4706     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4707     /* Set labels */
4708     for (v = 0; v < numVertices; ++v) {
4709       if (out.pointmarkerlist[v]) {
4710         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4711       }
4712     }
4713     if (interpolate) {
4714       PetscInt e;
4715 
4716       for (e = 0; e < out.numberofedges; e++) {
4717         if (out.edgemarkerlist[e]) {
4718           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4719           const PetscInt *edges;
4720           PetscInt        numEdges;
4721 
4722           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4723           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4724           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4725           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4726         }
4727       }
4728     }
4729     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4730   }
4731 #if 0 /* Do not currently support holes */
4732   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4733 #endif
4734   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4735   PetscFunctionReturn(0);
4736 }
4737 #endif
4738 
4739 #if defined(PETSC_HAVE_TETGEN)
4740 #include <tetgen.h>
4741 #undef __FUNCT__
4742 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4743 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4744 {
4745   MPI_Comm       comm;
4746   const PetscInt dim  = 3;
4747   ::tetgenio     in;
4748   ::tetgenio     out;
4749   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4750   PetscMPIInt    rank;
4751   PetscErrorCode ierr;
4752 
4753   PetscFunctionBegin;
4754   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4755   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4756   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4757   in.numberofpoints = vEnd - vStart;
4758   if (in.numberofpoints > 0) {
4759     PetscSection coordSection;
4760     Vec          coordinates;
4761     PetscScalar *array;
4762 
4763     in.pointlist       = new double[in.numberofpoints*dim];
4764     in.pointmarkerlist = new int[in.numberofpoints];
4765 
4766     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4767     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4768     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4769     for (v = vStart; v < vEnd; ++v) {
4770       const PetscInt idx = v - vStart;
4771       PetscInt       off, d;
4772 
4773       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4774       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
4775       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4776     }
4777     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4778   }
4779   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4780 
4781   in.numberoffacets = fEnd - fStart;
4782   if (in.numberoffacets > 0) {
4783     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4784     in.facetmarkerlist = new int[in.numberoffacets];
4785     for (f = fStart; f < fEnd; ++f) {
4786       const PetscInt idx     = f - fStart;
4787       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
4788 
4789       in.facetlist[idx].numberofpolygons = 1;
4790       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4791       in.facetlist[idx].numberofholes    = 0;
4792       in.facetlist[idx].holelist         = NULL;
4793 
4794       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4795       for (p = 0; p < numPoints*2; p += 2) {
4796         const PetscInt point = points[p];
4797         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4798       }
4799 
4800       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4801       poly->numberofvertices = numVertices;
4802       poly->vertexlist       = new int[poly->numberofvertices];
4803       for (v = 0; v < numVertices; ++v) {
4804         const PetscInt vIdx = points[v] - vStart;
4805         poly->vertexlist[v] = vIdx;
4806       }
4807       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4808       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4809     }
4810   }
4811   if (!rank) {
4812     char args[32];
4813 
4814     /* Take away 'Q' for verbose output */
4815     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4816     ::tetrahedralize(args, &in, &out);
4817   }
4818   {
4819     const PetscInt numCorners  = 4;
4820     const PetscInt numCells    = out.numberoftetrahedra;
4821     const PetscInt numVertices = out.numberofpoints;
4822     const int     *cells      = out.tetrahedronlist;
4823     const double  *meshCoords = out.pointlist;
4824 
4825     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4826     /* Set labels */
4827     for (v = 0; v < numVertices; ++v) {
4828       if (out.pointmarkerlist[v]) {
4829         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4830       }
4831     }
4832     if (interpolate) {
4833       PetscInt e;
4834 
4835       for (e = 0; e < out.numberofedges; e++) {
4836         if (out.edgemarkerlist[e]) {
4837           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4838           const PetscInt *edges;
4839           PetscInt        numEdges;
4840 
4841           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4842           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4843           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4844           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4845         }
4846       }
4847       for (f = 0; f < out.numberoftrifaces; f++) {
4848         if (out.trifacemarkerlist[f]) {
4849           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4850           const PetscInt *faces;
4851           PetscInt        numFaces;
4852 
4853           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4854           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4855           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4856           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4857         }
4858       }
4859     }
4860     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4861   }
4862   PetscFunctionReturn(0);
4863 }
4864 
4865 #undef __FUNCT__
4866 #define __FUNCT__ "DMPlexRefine_Tetgen"
4867 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4868 {
4869   MPI_Comm       comm;
4870   const PetscInt dim  = 3;
4871   ::tetgenio     in;
4872   ::tetgenio     out;
4873   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4874   PetscMPIInt    rank;
4875   PetscErrorCode ierr;
4876 
4877   PetscFunctionBegin;
4878   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4879   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4880   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4881   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4882   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4883 
4884   in.numberofpoints = vEnd - vStart;
4885   if (in.numberofpoints > 0) {
4886     PetscSection coordSection;
4887     Vec          coordinates;
4888     PetscScalar *array;
4889 
4890     in.pointlist       = new double[in.numberofpoints*dim];
4891     in.pointmarkerlist = new int[in.numberofpoints];
4892 
4893     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4894     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4895     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4896     for (v = vStart; v < vEnd; ++v) {
4897       const PetscInt idx = v - vStart;
4898       PetscInt       off, d;
4899 
4900       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4901       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
4902       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4903     }
4904     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4905   }
4906   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4907 
4908   in.numberofcorners       = 4;
4909   in.numberoftetrahedra    = cEnd - cStart;
4910   in.tetrahedronvolumelist = (double*) maxVolumes;
4911   if (in.numberoftetrahedra > 0) {
4912     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
4913     for (c = cStart; c < cEnd; ++c) {
4914       const PetscInt idx      = c - cStart;
4915       PetscInt      *closure = NULL;
4916       PetscInt       closureSize;
4917 
4918       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4919       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4920       for (v = 0; v < 4; ++v) {
4921         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4922       }
4923       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4924     }
4925   }
4926   /* TODO: Put in boundary faces with markers */
4927   if (!rank) {
4928     char args[32];
4929 
4930     /* Take away 'Q' for verbose output */
4931     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
4932     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
4933     ::tetrahedralize(args, &in, &out);
4934   }
4935   in.tetrahedronvolumelist = NULL;
4936 
4937   {
4938     const PetscInt numCorners  = 4;
4939     const PetscInt numCells    = out.numberoftetrahedra;
4940     const PetscInt numVertices = out.numberofpoints;
4941     const int     *cells      = out.tetrahedronlist;
4942     const double  *meshCoords = out.pointlist;
4943     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4944 
4945     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4946     /* Set labels */
4947     for (v = 0; v < numVertices; ++v) {
4948       if (out.pointmarkerlist[v]) {
4949         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4950       }
4951     }
4952     if (interpolate) {
4953       PetscInt e, f;
4954 
4955       for (e = 0; e < out.numberofedges; e++) {
4956         if (out.edgemarkerlist[e]) {
4957           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4958           const PetscInt *edges;
4959           PetscInt        numEdges;
4960 
4961           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4962           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4963           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4964           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4965         }
4966       }
4967       for (f = 0; f < out.numberoftrifaces; f++) {
4968         if (out.trifacemarkerlist[f]) {
4969           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4970           const PetscInt *faces;
4971           PetscInt        numFaces;
4972 
4973           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4974           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4975           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4976           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4977         }
4978       }
4979     }
4980     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4981   }
4982   PetscFunctionReturn(0);
4983 }
4984 #endif
4985 
4986 #if defined(PETSC_HAVE_CTETGEN)
4987 #include "ctetgen.h"
4988 
4989 #undef __FUNCT__
4990 #define __FUNCT__ "DMPlexGenerate_CTetgen"
4991 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4992 {
4993   MPI_Comm       comm;
4994   const PetscInt dim  = 3;
4995   PLC           *in, *out;
4996   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4997   PetscMPIInt    rank;
4998   PetscErrorCode ierr;
4999 
5000   PetscFunctionBegin;
5001   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5002   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5003   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5004   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5005   ierr = PLCCreate(&in);CHKERRQ(ierr);
5006   ierr = PLCCreate(&out);CHKERRQ(ierr);
5007 
5008   in->numberofpoints = vEnd - vStart;
5009   if (in->numberofpoints > 0) {
5010     PetscSection coordSection;
5011     Vec          coordinates;
5012     PetscScalar *array;
5013 
5014     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5015     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5016     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5017     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5018     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5019     for (v = vStart; v < vEnd; ++v) {
5020       const PetscInt idx = v - vStart;
5021       PetscInt       off, d, m;
5022 
5023       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5024       for (d = 0; d < dim; ++d) {
5025         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5026       }
5027       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5028 
5029       in->pointmarkerlist[idx] = (int) m;
5030     }
5031     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5032   }
5033   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5034 
5035   in->numberoffacets = fEnd - fStart;
5036   if (in->numberoffacets > 0) {
5037     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5038     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5039     for (f = fStart; f < fEnd; ++f) {
5040       const PetscInt idx     = f - fStart;
5041       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5042       polygon       *poly;
5043 
5044       in->facetlist[idx].numberofpolygons = 1;
5045 
5046       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5047 
5048       in->facetlist[idx].numberofholes    = 0;
5049       in->facetlist[idx].holelist         = NULL;
5050 
5051       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5052       for (p = 0; p < numPoints*2; p += 2) {
5053         const PetscInt point = points[p];
5054         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5055       }
5056 
5057       poly                   = in->facetlist[idx].polygonlist;
5058       poly->numberofvertices = numVertices;
5059       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5060       for (v = 0; v < numVertices; ++v) {
5061         const PetscInt vIdx = points[v] - vStart;
5062         poly->vertexlist[v] = vIdx;
5063       }
5064       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5065       in->facetmarkerlist[idx] = (int) m;
5066       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5067     }
5068   }
5069   if (!rank) {
5070     TetGenOpts t;
5071 
5072     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5073     t.in        = boundary; /* Should go away */
5074     t.plc       = 1;
5075     t.quality   = 1;
5076     t.edgesout  = 1;
5077     t.zeroindex = 1;
5078     t.quiet     = 1;
5079     t.verbose   = verbose;
5080     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5081     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5082   }
5083   {
5084     const PetscInt numCorners  = 4;
5085     const PetscInt numCells    = out->numberoftetrahedra;
5086     const PetscInt numVertices = out->numberofpoints;
5087     const int     *cells      = out->tetrahedronlist;
5088     const double  *meshCoords = out->pointlist;
5089 
5090     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
5091     /* Set labels */
5092     for (v = 0; v < numVertices; ++v) {
5093       if (out->pointmarkerlist[v]) {
5094         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5095       }
5096     }
5097     if (interpolate) {
5098       PetscInt e;
5099 
5100       for (e = 0; e < out->numberofedges; e++) {
5101         if (out->edgemarkerlist[e]) {
5102           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5103           const PetscInt *edges;
5104           PetscInt        numEdges;
5105 
5106           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5107           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5108           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5109           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5110         }
5111       }
5112       for (f = 0; f < out->numberoftrifaces; f++) {
5113         if (out->trifacemarkerlist[f]) {
5114           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5115           const PetscInt *faces;
5116           PetscInt        numFaces;
5117 
5118           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5119           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5120           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5121           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5122         }
5123       }
5124     }
5125     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5126   }
5127 
5128   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5129   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5130   PetscFunctionReturn(0);
5131 }
5132 
5133 #undef __FUNCT__
5134 #define __FUNCT__ "DMPlexRefine_CTetgen"
5135 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5136 {
5137   MPI_Comm       comm;
5138   const PetscInt dim  = 3;
5139   PLC           *in, *out;
5140   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5141   PetscMPIInt    rank;
5142   PetscErrorCode ierr;
5143 
5144   PetscFunctionBegin;
5145   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5146   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5147   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5148   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5149   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5150   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5151   ierr = PLCCreate(&in);CHKERRQ(ierr);
5152   ierr = PLCCreate(&out);CHKERRQ(ierr);
5153 
5154   in->numberofpoints = vEnd - vStart;
5155   if (in->numberofpoints > 0) {
5156     PetscSection coordSection;
5157     Vec          coordinates;
5158     PetscScalar *array;
5159 
5160     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5161     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5162     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5163     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5164     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5165     for (v = vStart; v < vEnd; ++v) {
5166       const PetscInt idx = v - vStart;
5167       PetscInt       off, d, m;
5168 
5169       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5170       for (d = 0; d < dim; ++d) {
5171         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5172       }
5173       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5174 
5175       in->pointmarkerlist[idx] = (int) m;
5176     }
5177     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5178   }
5179   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5180 
5181   in->numberofcorners       = 4;
5182   in->numberoftetrahedra    = cEnd - cStart;
5183   in->tetrahedronvolumelist = maxVolumes;
5184   if (in->numberoftetrahedra > 0) {
5185     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5186     for (c = cStart; c < cEnd; ++c) {
5187       const PetscInt idx      = c - cStart;
5188       PetscInt      *closure = NULL;
5189       PetscInt       closureSize;
5190 
5191       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5192       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5193       for (v = 0; v < 4; ++v) {
5194         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5195       }
5196       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5197     }
5198   }
5199   if (!rank) {
5200     TetGenOpts t;
5201 
5202     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5203 
5204     t.in        = dm; /* Should go away */
5205     t.refine    = 1;
5206     t.varvolume = 1;
5207     t.quality   = 1;
5208     t.edgesout  = 1;
5209     t.zeroindex = 1;
5210     t.quiet     = 1;
5211     t.verbose   = verbose; /* Change this */
5212 
5213     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5214     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5215   }
5216   {
5217     const PetscInt numCorners  = 4;
5218     const PetscInt numCells    = out->numberoftetrahedra;
5219     const PetscInt numVertices = out->numberofpoints;
5220     const int     *cells       = out->tetrahedronlist;
5221     const double  *meshCoords  = out->pointlist;
5222     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5223 
5224     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
5225     /* Set labels */
5226     for (v = 0; v < numVertices; ++v) {
5227       if (out->pointmarkerlist[v]) {
5228         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5229       }
5230     }
5231     if (interpolate) {
5232       PetscInt e, f;
5233 
5234       for (e = 0; e < out->numberofedges; e++) {
5235         if (out->edgemarkerlist[e]) {
5236           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5237           const PetscInt *edges;
5238           PetscInt        numEdges;
5239 
5240           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5241           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5242           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5243           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5244         }
5245       }
5246       for (f = 0; f < out->numberoftrifaces; f++) {
5247         if (out->trifacemarkerlist[f]) {
5248           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5249           const PetscInt *faces;
5250           PetscInt        numFaces;
5251 
5252           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5253           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5254           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5255           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5256         }
5257       }
5258     }
5259     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5260   }
5261   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5262   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5263   PetscFunctionReturn(0);
5264 }
5265 #endif
5266 
5267 #undef __FUNCT__
5268 #define __FUNCT__ "DMPlexGenerate"
5269 /*@C
5270   DMPlexGenerate - Generates a mesh.
5271 
5272   Not Collective
5273 
5274   Input Parameters:
5275 + boundary - The DMPlex boundary object
5276 . name - The mesh generation package name
5277 - interpolate - Flag to create intermediate mesh elements
5278 
5279   Output Parameter:
5280 . mesh - The DMPlex object
5281 
5282   Level: intermediate
5283 
5284 .keywords: mesh, elements
5285 .seealso: DMPlexCreate(), DMRefine()
5286 @*/
5287 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5288 {
5289   PetscInt       dim;
5290   char           genname[1024];
5291   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5292   PetscErrorCode ierr;
5293 
5294   PetscFunctionBegin;
5295   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5296   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5297   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5298   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5299   if (flg) name = genname;
5300   if (name) {
5301     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5302     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5303     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5304   }
5305   switch (dim) {
5306   case 1:
5307     if (!name || isTriangle) {
5308 #if defined(PETSC_HAVE_TRIANGLE)
5309       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5310 #else
5311       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5312 #endif
5313     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5314     break;
5315   case 2:
5316     if (!name || isCTetgen) {
5317 #if defined(PETSC_HAVE_CTETGEN)
5318       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5319 #else
5320       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5321 #endif
5322     } else if (isTetgen) {
5323 #if defined(PETSC_HAVE_TETGEN)
5324       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5325 #else
5326       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5327 #endif
5328     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5329     break;
5330   default:
5331     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5332   }
5333   PetscFunctionReturn(0);
5334 }
5335 
5336 typedef PetscInt CellRefiner;
5337 
5338 #undef __FUNCT__
5339 #define __FUNCT__ "GetDepthStart_Private"
5340 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5341 {
5342   PetscFunctionBegin;
5343   if (cStart) *cStart = 0;
5344   if (vStart) *vStart = depthSize[depth];
5345   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5346   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5347   PetscFunctionReturn(0);
5348 }
5349 
5350 #undef __FUNCT__
5351 #define __FUNCT__ "GetDepthEnd_Private"
5352 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5353 {
5354   PetscFunctionBegin;
5355   if (cEnd) *cEnd = depthSize[depth];
5356   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5357   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5358   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5359   PetscFunctionReturn(0);
5360 }
5361 
5362 #undef __FUNCT__
5363 #define __FUNCT__ "CellRefinerGetSizes"
5364 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5365 {
5366   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5367   PetscErrorCode ierr;
5368 
5369   PetscFunctionBegin;
5370   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5371   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5372   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5373   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5374   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5375   switch (refiner) {
5376   case 1:
5377     /* Simplicial 2D */
5378     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5379     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5380     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5381     break;
5382   case 3:
5383     /* Hybrid 2D */
5384     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5385     cMax = PetscMin(cEnd, cMax);
5386     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5387     fMax         = PetscMin(fEnd, fMax);
5388     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5389     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 */
5390     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5391     break;
5392   case 2:
5393     /* Hex 2D */
5394     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5395     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5396     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5397     break;
5398   default:
5399     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5400   }
5401   PetscFunctionReturn(0);
5402 }
5403 
5404 #undef __FUNCT__
5405 #define __FUNCT__ "CellRefinerSetConeSizes"
5406 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5407 {
5408   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5409   PetscErrorCode ierr;
5410 
5411   PetscFunctionBegin;
5412   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5413   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5414   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5415   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5416   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5417   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5418   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5419   switch (refiner) {
5420   case 1:
5421     /* Simplicial 2D */
5422     /* All cells have 3 faces */
5423     for (c = cStart; c < cEnd; ++c) {
5424       for (r = 0; r < 4; ++r) {
5425         const PetscInt newp = (c - cStart)*4 + r;
5426 
5427         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5428       }
5429     }
5430     /* Split faces have 2 vertices and the same cells as the parent */
5431     for (f = fStart; f < fEnd; ++f) {
5432       for (r = 0; r < 2; ++r) {
5433         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5434         PetscInt       size;
5435 
5436         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5437         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5438         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5439       }
5440     }
5441     /* Interior faces have 2 vertices and 2 cells */
5442     for (c = cStart; c < cEnd; ++c) {
5443       for (r = 0; r < 3; ++r) {
5444         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5445 
5446         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5447         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5448       }
5449     }
5450     /* Old vertices have identical supports */
5451     for (v = vStart; v < vEnd; ++v) {
5452       const PetscInt newp = vStartNew + (v - vStart);
5453       PetscInt       size;
5454 
5455       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5456       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5457     }
5458     /* Face vertices have 2 + cells*2 supports */
5459     for (f = fStart; f < fEnd; ++f) {
5460       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5461       PetscInt       size;
5462 
5463       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5464       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5465     }
5466     break;
5467   case 2:
5468     /* Hex 2D */
5469     /* All cells have 4 faces */
5470     for (c = cStart; c < cEnd; ++c) {
5471       for (r = 0; r < 4; ++r) {
5472         const PetscInt newp = (c - cStart)*4 + r;
5473 
5474         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5475       }
5476     }
5477     /* Split faces have 2 vertices and the same cells as the parent */
5478     for (f = fStart; f < fEnd; ++f) {
5479       for (r = 0; r < 2; ++r) {
5480         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5481         PetscInt       size;
5482 
5483         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5484         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5485         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5486       }
5487     }
5488     /* Interior faces have 2 vertices and 2 cells */
5489     for (c = cStart; c < cEnd; ++c) {
5490       for (r = 0; r < 4; ++r) {
5491         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5492 
5493         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5494         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5495       }
5496     }
5497     /* Old vertices have identical supports */
5498     for (v = vStart; v < vEnd; ++v) {
5499       const PetscInt newp = vStartNew + (v - vStart);
5500       PetscInt       size;
5501 
5502       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5503       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5504     }
5505     /* Face vertices have 2 + cells supports */
5506     for (f = fStart; f < fEnd; ++f) {
5507       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5508       PetscInt       size;
5509 
5510       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5511       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5512     }
5513     /* Cell vertices have 4 supports */
5514     for (c = cStart; c < cEnd; ++c) {
5515       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5516 
5517       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5518     }
5519     break;
5520   case 3:
5521     /* Hybrid 2D */
5522     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5523     cMax = PetscMin(cEnd, cMax);
5524     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5525     fMax = PetscMin(fEnd, fMax);
5526     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5527     /* Interior cells have 3 faces */
5528     for (c = cStart; c < cMax; ++c) {
5529       for (r = 0; r < 4; ++r) {
5530         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5531 
5532         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5533       }
5534     }
5535     /* Hybrid cells have 4 faces */
5536     for (c = cMax; c < cEnd; ++c) {
5537       for (r = 0; r < 2; ++r) {
5538         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5539 
5540         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5541       }
5542     }
5543     /* Interior split faces have 2 vertices and the same cells as the parent */
5544     for (f = fStart; f < fMax; ++f) {
5545       for (r = 0; r < 2; ++r) {
5546         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5547         PetscInt       size;
5548 
5549         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5550         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5551         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5552       }
5553     }
5554     /* Interior cell faces have 2 vertices and 2 cells */
5555     for (c = cStart; c < cMax; ++c) {
5556       for (r = 0; r < 3; ++r) {
5557         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5558 
5559         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5560         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5561       }
5562     }
5563     /* Hybrid faces have 2 vertices and the same cells */
5564     for (f = fMax; f < fEnd; ++f) {
5565       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5566       PetscInt       size;
5567 
5568       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5569       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5570       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5571     }
5572     /* Hybrid cell faces have 2 vertices and 2 cells */
5573     for (c = cMax; c < cEnd; ++c) {
5574       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5575 
5576       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5577       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5578     }
5579     /* Old vertices have identical supports */
5580     for (v = vStart; v < vEnd; ++v) {
5581       const PetscInt newp = vStartNew + (v - vStart);
5582       PetscInt       size;
5583 
5584       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5585       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5586     }
5587     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5588     for (f = fStart; f < fMax; ++f) {
5589       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5590       const PetscInt *support;
5591       PetscInt       size, newSize = 2, s;
5592 
5593       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5594       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5595       for (s = 0; s < size; ++s) {
5596         if (support[s] >= cMax) newSize += 1;
5597         else newSize += 2;
5598       }
5599       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5600     }
5601     break;
5602   default:
5603     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5604   }
5605   PetscFunctionReturn(0);
5606 }
5607 
5608 #undef __FUNCT__
5609 #define __FUNCT__ "CellRefinerSetCones"
5610 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5611 {
5612   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;
5613   PetscInt       maxSupportSize, *supportRef;
5614   PetscErrorCode ierr;
5615 
5616   PetscFunctionBegin;
5617   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5618   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5619   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5620   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5621   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5622   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5623   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5624   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5625   switch (refiner) {
5626   case 1:
5627     /* Simplicial 2D */
5628     /*
5629      2
5630      |\
5631      | \
5632      |  \
5633      |   \
5634      | C  \
5635      |     \
5636      |      \
5637      2---1---1
5638      |\  D  / \
5639      | 2   0   \
5640      |A \ /  B  \
5641      0---0-------1
5642      */
5643     /* All cells have 3 faces */
5644     for (c = cStart; c < cEnd; ++c) {
5645       const PetscInt  newp = cStartNew + (c - cStart)*4;
5646       const PetscInt *cone, *ornt;
5647       PetscInt        coneNew[3], orntNew[3];
5648 
5649       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5650       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5651       /* A triangle */
5652       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5653       orntNew[0] = ornt[0];
5654       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5655       orntNew[1] = -2;
5656       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5657       orntNew[2] = ornt[2];
5658       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5659       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5660 #if 1
5661       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);
5662       for (p = 0; p < 3; ++p) {
5663         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);
5664       }
5665 #endif
5666       /* B triangle */
5667       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5668       orntNew[0] = ornt[0];
5669       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5670       orntNew[1] = ornt[1];
5671       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5672       orntNew[2] = -2;
5673       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5674       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5675 #if 1
5676       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);
5677       for (p = 0; p < 3; ++p) {
5678         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);
5679       }
5680 #endif
5681       /* C triangle */
5682       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5683       orntNew[0] = -2;
5684       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5685       orntNew[1] = ornt[1];
5686       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5687       orntNew[2] = ornt[2];
5688       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5689       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5690 #if 1
5691       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);
5692       for (p = 0; p < 3; ++p) {
5693         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);
5694       }
5695 #endif
5696       /* D triangle */
5697       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5698       orntNew[0] = 0;
5699       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5700       orntNew[1] = 0;
5701       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5702       orntNew[2] = 0;
5703       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5704       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5705 #if 1
5706       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);
5707       for (p = 0; p < 3; ++p) {
5708         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);
5709       }
5710 #endif
5711     }
5712     /* Split faces have 2 vertices and the same cells as the parent */
5713     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5714     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5715     for (f = fStart; f < fEnd; ++f) {
5716       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5717 
5718       for (r = 0; r < 2; ++r) {
5719         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5720         const PetscInt *cone, *support;
5721         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5722 
5723         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5724         coneNew[0]       = vStartNew + (cone[0] - vStart);
5725         coneNew[1]       = vStartNew + (cone[1] - vStart);
5726         coneNew[(r+1)%2] = newv;
5727         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5728 #if 1
5729         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5730         for (p = 0; p < 2; ++p) {
5731           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);
5732         }
5733 #endif
5734         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5735         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5736         for (s = 0; s < supportSize; ++s) {
5737           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5738           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5739           for (c = 0; c < coneSize; ++c) {
5740             if (cone[c] == f) break;
5741           }
5742           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5743         }
5744         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5745 #if 1
5746         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5747         for (p = 0; p < supportSize; ++p) {
5748           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);
5749         }
5750 #endif
5751       }
5752     }
5753     /* Interior faces have 2 vertices and 2 cells */
5754     for (c = cStart; c < cEnd; ++c) {
5755       const PetscInt *cone;
5756 
5757       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5758       for (r = 0; r < 3; ++r) {
5759         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5760         PetscInt       coneNew[2];
5761         PetscInt       supportNew[2];
5762 
5763         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5764         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5765         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5766 #if 1
5767         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5768         for (p = 0; p < 2; ++p) {
5769           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);
5770         }
5771 #endif
5772         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5773         supportNew[1] = (c - cStart)*4 + 3;
5774         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5775 #if 1
5776         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5777         for (p = 0; p < 2; ++p) {
5778           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);
5779         }
5780 #endif
5781       }
5782     }
5783     /* Old vertices have identical supports */
5784     for (v = vStart; v < vEnd; ++v) {
5785       const PetscInt  newp = vStartNew + (v - vStart);
5786       const PetscInt *support, *cone;
5787       PetscInt        size, s;
5788 
5789       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5790       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5791       for (s = 0; s < size; ++s) {
5792         PetscInt r = 0;
5793 
5794         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5795         if (cone[1] == v) r = 1;
5796         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5797       }
5798       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5799 #if 1
5800       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5801       for (p = 0; p < size; ++p) {
5802         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);
5803       }
5804 #endif
5805     }
5806     /* Face vertices have 2 + cells*2 supports */
5807     for (f = fStart; f < fEnd; ++f) {
5808       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5809       const PetscInt *cone, *support;
5810       PetscInt        size, s;
5811 
5812       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5813       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5814       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5815       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5816       for (s = 0; s < size; ++s) {
5817         PetscInt r = 0;
5818 
5819         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5820         if      (cone[1] == f) r = 1;
5821         else if (cone[2] == f) r = 2;
5822         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5823         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5824       }
5825       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5826 #if 1
5827       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5828       for (p = 0; p < 2+size*2; ++p) {
5829         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);
5830       }
5831 #endif
5832     }
5833     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5834     break;
5835   case 2:
5836     /* Hex 2D */
5837     /*
5838      3---------2---------2
5839      |         |         |
5840      |    D    2    C    |
5841      |         |         |
5842      3----3----0----1----1
5843      |         |         |
5844      |    A    0    B    |
5845      |         |         |
5846      0---------0---------1
5847      */
5848     /* All cells have 4 faces */
5849     for (c = cStart; c < cEnd; ++c) {
5850       const PetscInt  newp = (c - cStart)*4;
5851       const PetscInt *cone, *ornt;
5852       PetscInt        coneNew[4], orntNew[4];
5853 
5854       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5855       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5856       /* A quad */
5857       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5858       orntNew[0] = ornt[0];
5859       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5860       orntNew[1] = 0;
5861       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5862       orntNew[2] = -2;
5863       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5864       orntNew[3] = ornt[3];
5865       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5866       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5867 #if 1
5868       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);
5869       for (p = 0; p < 4; ++p) {
5870         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);
5871       }
5872 #endif
5873       /* B quad */
5874       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5875       orntNew[0] = ornt[0];
5876       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5877       orntNew[1] = ornt[1];
5878       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5879       orntNew[2] = 0;
5880       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5881       orntNew[3] = -2;
5882       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5883       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5884 #if 1
5885       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);
5886       for (p = 0; p < 4; ++p) {
5887         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);
5888       }
5889 #endif
5890       /* C quad */
5891       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5892       orntNew[0] = -2;
5893       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5894       orntNew[1] = ornt[1];
5895       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5896       orntNew[2] = ornt[2];
5897       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5898       orntNew[3] = 0;
5899       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5900       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5901 #if 1
5902       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);
5903       for (p = 0; p < 4; ++p) {
5904         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);
5905       }
5906 #endif
5907       /* D quad */
5908       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5909       orntNew[0] = 0;
5910       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5911       orntNew[1] = -2;
5912       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5913       orntNew[2] = ornt[2];
5914       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
5915       orntNew[3] = ornt[3];
5916       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5917       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5918 #if 1
5919       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);
5920       for (p = 0; p < 4; ++p) {
5921         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);
5922       }
5923 #endif
5924     }
5925     /* Split faces have 2 vertices and the same cells as the parent */
5926     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5927     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5928     for (f = fStart; f < fEnd; ++f) {
5929       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5930 
5931       for (r = 0; r < 2; ++r) {
5932         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5933         const PetscInt *cone, *support;
5934         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5935 
5936         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5937         coneNew[0]       = vStartNew + (cone[0] - vStart);
5938         coneNew[1]       = vStartNew + (cone[1] - vStart);
5939         coneNew[(r+1)%2] = newv;
5940         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5941 #if 1
5942         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5943         for (p = 0; p < 2; ++p) {
5944           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);
5945         }
5946 #endif
5947         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5948         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5949         for (s = 0; s < supportSize; ++s) {
5950           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5951           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5952           for (c = 0; c < coneSize; ++c) {
5953             if (cone[c] == f) break;
5954           }
5955           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
5956         }
5957         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5958 #if 1
5959         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5960         for (p = 0; p < supportSize; ++p) {
5961           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);
5962         }
5963 #endif
5964       }
5965     }
5966     /* Interior faces have 2 vertices and 2 cells */
5967     for (c = cStart; c < cEnd; ++c) {
5968       const PetscInt *cone;
5969       PetscInt        coneNew[2], supportNew[2];
5970 
5971       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5972       for (r = 0; r < 4; ++r) {
5973         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5974 
5975         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
5976         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
5977         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5978 #if 1
5979         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5980         for (p = 0; p < 2; ++p) {
5981           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);
5982         }
5983 #endif
5984         supportNew[0] = (c - cStart)*4 + r;
5985         supportNew[1] = (c - cStart)*4 + (r+1)%4;
5986         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5987 #if 1
5988         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5989         for (p = 0; p < 2; ++p) {
5990           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);
5991         }
5992 #endif
5993       }
5994     }
5995     /* Old vertices have identical supports */
5996     for (v = vStart; v < vEnd; ++v) {
5997       const PetscInt  newp = vStartNew + (v - vStart);
5998       const PetscInt *support, *cone;
5999       PetscInt        size, s;
6000 
6001       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6002       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6003       for (s = 0; s < size; ++s) {
6004         PetscInt r = 0;
6005 
6006         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6007         if (cone[1] == v) r = 1;
6008         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6009       }
6010       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6011 #if 1
6012       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6013       for (p = 0; p < size; ++p) {
6014         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);
6015       }
6016 #endif
6017     }
6018     /* Face vertices have 2 + cells supports */
6019     for (f = fStart; f < fEnd; ++f) {
6020       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6021       const PetscInt *cone, *support;
6022       PetscInt        size, s;
6023 
6024       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6025       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6026       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6027       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6028       for (s = 0; s < size; ++s) {
6029         PetscInt r = 0;
6030 
6031         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6032         if      (cone[1] == f) r = 1;
6033         else if (cone[2] == f) r = 2;
6034         else if (cone[3] == f) r = 3;
6035         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6036       }
6037       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6038 #if 1
6039       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6040       for (p = 0; p < 2+size; ++p) {
6041         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);
6042       }
6043 #endif
6044     }
6045     /* Cell vertices have 4 supports */
6046     for (c = cStart; c < cEnd; ++c) {
6047       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6048       PetscInt       supportNew[4];
6049 
6050       for (r = 0; r < 4; ++r) {
6051         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6052       }
6053       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6054     }
6055     break;
6056   case 3:
6057     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6058     cMax = PetscMin(cEnd, cMax);
6059     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6060     fMax = PetscMin(fEnd, fMax);
6061     /* Interior cells have 3 faces */
6062     for (c = cStart; c < cMax; ++c) {
6063       const PetscInt  newp = cStartNew + (c - cStart)*4;
6064       const PetscInt *cone, *ornt;
6065       PetscInt        coneNew[3], orntNew[3];
6066 
6067       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6068       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6069       /* A triangle */
6070       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6071       orntNew[0] = ornt[0];
6072       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6073       orntNew[1] = -2;
6074       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6075       orntNew[2] = ornt[2];
6076       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6077       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6078 #if 1
6079       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);
6080       for (p = 0; p < 3; ++p) {
6081         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);
6082       }
6083 #endif
6084       /* B triangle */
6085       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6086       orntNew[0] = ornt[0];
6087       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6088       orntNew[1] = ornt[1];
6089       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6090       orntNew[2] = -2;
6091       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6092       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6093 #if 1
6094       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);
6095       for (p = 0; p < 3; ++p) {
6096         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);
6097       }
6098 #endif
6099       /* C triangle */
6100       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6101       orntNew[0] = -2;
6102       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6103       orntNew[1] = ornt[1];
6104       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6105       orntNew[2] = ornt[2];
6106       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6107       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6108 #if 1
6109       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);
6110       for (p = 0; p < 3; ++p) {
6111         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);
6112       }
6113 #endif
6114       /* D triangle */
6115       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6116       orntNew[0] = 0;
6117       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6118       orntNew[1] = 0;
6119       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6120       orntNew[2] = 0;
6121       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6122       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6123 #if 1
6124       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);
6125       for (p = 0; p < 3; ++p) {
6126         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);
6127       }
6128 #endif
6129     }
6130     /*
6131      2----3----3
6132      |         |
6133      |    B    |
6134      |         |
6135      0----4--- 1
6136      |         |
6137      |    A    |
6138      |         |
6139      0----2----1
6140      */
6141     /* Hybrid cells have 4 faces */
6142     for (c = cMax; c < cEnd; ++c) {
6143       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6144       const PetscInt *cone, *ornt;
6145       PetscInt        coneNew[4], orntNew[4];
6146 
6147       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6148       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6149       /* A quad */
6150       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6151       orntNew[0] = ornt[0];
6152       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6153       orntNew[1] = ornt[1];
6154       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6155       orntNew[2] = 0;
6156       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6157       orntNew[3] = 0;
6158       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6159       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6160 #if 1
6161       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);
6162       for (p = 0; p < 4; ++p) {
6163         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);
6164       }
6165 #endif
6166       /* B quad */
6167       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6168       orntNew[0] = ornt[0];
6169       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6170       orntNew[1] = ornt[1];
6171       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6172       orntNew[2] = 0;
6173       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6174       orntNew[3] = 0;
6175       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6176       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6177 #if 1
6178       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);
6179       for (p = 0; p < 4; ++p) {
6180         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);
6181       }
6182 #endif
6183     }
6184     /* Interior split faces have 2 vertices and the same cells as the parent */
6185     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6186     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6187     for (f = fStart; f < fMax; ++f) {
6188       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6189 
6190       for (r = 0; r < 2; ++r) {
6191         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6192         const PetscInt *cone, *support;
6193         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6194 
6195         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6196         coneNew[0]       = vStartNew + (cone[0] - vStart);
6197         coneNew[1]       = vStartNew + (cone[1] - vStart);
6198         coneNew[(r+1)%2] = newv;
6199         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6200 #if 1
6201         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6202         for (p = 0; p < 2; ++p) {
6203           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);
6204         }
6205 #endif
6206         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6207         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6208         for (s = 0; s < supportSize; ++s) {
6209           if (support[s] >= cMax) {
6210             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6211           } else {
6212             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6213             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6214             for (c = 0; c < coneSize; ++c) {
6215               if (cone[c] == f) break;
6216             }
6217             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6218           }
6219         }
6220         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6221 #if 1
6222         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6223         for (p = 0; p < supportSize; ++p) {
6224           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);
6225         }
6226 #endif
6227       }
6228     }
6229     /* Interior cell faces have 2 vertices and 2 cells */
6230     for (c = cStart; c < cMax; ++c) {
6231       const PetscInt *cone;
6232 
6233       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6234       for (r = 0; r < 3; ++r) {
6235         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6236         PetscInt       coneNew[2];
6237         PetscInt       supportNew[2];
6238 
6239         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6240         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6241         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6242 #if 1
6243         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6244         for (p = 0; p < 2; ++p) {
6245           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);
6246         }
6247 #endif
6248         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6249         supportNew[1] = (c - cStart)*4 + 3;
6250         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6251 #if 1
6252         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6253         for (p = 0; p < 2; ++p) {
6254           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);
6255         }
6256 #endif
6257       }
6258     }
6259     /* Interior hybrid faces have 2 vertices and the same cells */
6260     for (f = fMax; f < fEnd; ++f) {
6261       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6262       const PetscInt *cone;
6263       const PetscInt *support;
6264       PetscInt        coneNew[2];
6265       PetscInt        supportNew[2];
6266       PetscInt        size, s, r;
6267 
6268       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6269       coneNew[0] = vStartNew + (cone[0] - vStart);
6270       coneNew[1] = vStartNew + (cone[1] - vStart);
6271       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6272 #if 1
6273       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6274       for (p = 0; p < 2; ++p) {
6275         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);
6276       }
6277 #endif
6278       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6279       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6280       for (s = 0; s < size; ++s) {
6281         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6282         for (r = 0; r < 2; ++r) {
6283           if (cone[r+2] == f) break;
6284         }
6285         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6286       }
6287       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6288 #if 1
6289       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6290       for (p = 0; p < size; ++p) {
6291         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);
6292       }
6293 #endif
6294     }
6295     /* Cell hybrid faces have 2 vertices and 2 cells */
6296     for (c = cMax; c < cEnd; ++c) {
6297       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6298       const PetscInt *cone;
6299       PetscInt        coneNew[2];
6300       PetscInt        supportNew[2];
6301 
6302       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6303       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6304       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6305       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6306 #if 1
6307       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6308       for (p = 0; p < 2; ++p) {
6309         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);
6310       }
6311 #endif
6312       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6313       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6314       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6315 #if 1
6316       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6317       for (p = 0; p < 2; ++p) {
6318         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);
6319       }
6320 #endif
6321     }
6322     /* Old vertices have identical supports */
6323     for (v = vStart; v < vEnd; ++v) {
6324       const PetscInt  newp = vStartNew + (v - vStart);
6325       const PetscInt *support, *cone;
6326       PetscInt        size, s;
6327 
6328       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6329       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6330       for (s = 0; s < size; ++s) {
6331         if (support[s] >= fMax) {
6332           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6333         } else {
6334           PetscInt r = 0;
6335 
6336           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6337           if (cone[1] == v) r = 1;
6338           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6339         }
6340       }
6341       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6342 #if 1
6343       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6344       for (p = 0; p < size; ++p) {
6345         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);
6346       }
6347 #endif
6348     }
6349     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6350     for (f = fStart; f < fMax; ++f) {
6351       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6352       const PetscInt *cone, *support;
6353       PetscInt        size, newSize = 2, s;
6354 
6355       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6356       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6357       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6358       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6359       for (s = 0; s < size; ++s) {
6360         PetscInt r = 0;
6361 
6362         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6363         if (support[s] >= cMax) {
6364           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6365 
6366           newSize += 1;
6367         } else {
6368           if      (cone[1] == f) r = 1;
6369           else if (cone[2] == f) r = 2;
6370           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6371           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6372 
6373           newSize += 2;
6374         }
6375       }
6376       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6377 #if 1
6378       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6379       for (p = 0; p < newSize; ++p) {
6380         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);
6381       }
6382 #endif
6383     }
6384     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6385     break;
6386   default:
6387     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6388   }
6389   PetscFunctionReturn(0);
6390 }
6391 
6392 #undef __FUNCT__
6393 #define __FUNCT__ "CellRefinerSetCoordinates"
6394 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6395 {
6396   PetscSection   coordSection, coordSectionNew;
6397   Vec            coordinates, coordinatesNew;
6398   PetscScalar   *coords, *coordsNew;
6399   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6400   PetscErrorCode ierr;
6401 
6402   PetscFunctionBegin;
6403   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6404   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6405   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6406   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6407   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6408   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6409   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6410   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6411   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6412   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6413   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6414   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6415   if (fMax < 0) fMax = fEnd;
6416   switch (refiner) {
6417   case 1:
6418   case 2:
6419   case 3:
6420     /* Simplicial and Hex 2D */
6421     /* All vertices have the dim coordinates */
6422     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6423       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6424       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6425     }
6426     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6427     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6428     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6429     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6430     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
6431     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6432     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6433     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6434     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6435     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6436     /* Old vertices have the same coordinates */
6437     for (v = vStart; v < vEnd; ++v) {
6438       const PetscInt newv = vStartNew + (v - vStart);
6439       PetscInt       off, offnew, d;
6440 
6441       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6442       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6443       for (d = 0; d < dim; ++d) {
6444         coordsNew[offnew+d] = coords[off+d];
6445       }
6446     }
6447     /* Face vertices have the average of endpoint coordinates */
6448     for (f = fStart; f < fMax; ++f) {
6449       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6450       const PetscInt *cone;
6451       PetscInt        coneSize, offA, offB, offnew, d;
6452 
6453       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6454       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6455       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6456       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6457       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6458       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6459       for (d = 0; d < dim; ++d) {
6460         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6461       }
6462     }
6463     /* Just Hex 2D */
6464     if (refiner == 2) {
6465       /* Cell vertices have the average of corner coordinates */
6466       for (c = cStart; c < cEnd; ++c) {
6467         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6468         PetscInt      *cone = NULL;
6469         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6470 
6471         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6472         for (p = 0; p < closureSize*2; p += 2) {
6473           const PetscInt point = cone[p];
6474           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6475         }
6476         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6477         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6478         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6479         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6480         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6481         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6482         for (d = 0; d < dim; ++d) {
6483           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6484         }
6485         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6486       }
6487     }
6488     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6489     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6490     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6491     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6492     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
6493     break;
6494   default:
6495     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6496   }
6497   PetscFunctionReturn(0);
6498 }
6499 
6500 #undef __FUNCT__
6501 #define __FUNCT__ "DMPlexCreateProcessSF"
6502 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6503 {
6504   PetscInt           numRoots, numLeaves, l;
6505   const PetscInt    *localPoints;
6506   const PetscSFNode *remotePoints;
6507   PetscInt          *localPointsNew;
6508   PetscSFNode       *remotePointsNew;
6509   PetscInt          *ranks, *ranksNew;
6510   PetscErrorCode     ierr;
6511 
6512   PetscFunctionBegin;
6513   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6514   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6515   for (l = 0; l < numLeaves; ++l) {
6516     ranks[l] = remotePoints[l].rank;
6517   }
6518   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6519   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6520   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6521   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6522   for (l = 0; l < numLeaves; ++l) {
6523     ranksNew[l]              = ranks[l];
6524     localPointsNew[l]        = l;
6525     remotePointsNew[l].index = 0;
6526     remotePointsNew[l].rank  = ranksNew[l];
6527   }
6528   ierr = PetscFree(ranks);CHKERRQ(ierr);
6529   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6530   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
6531   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6532   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6533   PetscFunctionReturn(0);
6534 }
6535 
6536 #undef __FUNCT__
6537 #define __FUNCT__ "CellRefinerCreateSF"
6538 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6539 {
6540   PetscSF            sf, sfNew, sfProcess;
6541   IS                 processRanks;
6542   MPI_Datatype       depthType;
6543   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6544   const PetscInt    *localPoints, *neighbors;
6545   const PetscSFNode *remotePoints;
6546   PetscInt          *localPointsNew;
6547   PetscSFNode       *remotePointsNew;
6548   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6549   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6550   PetscErrorCode     ierr;
6551 
6552   PetscFunctionBegin;
6553   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6554   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6555   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6556   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6557   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6558   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6559   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6560   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6561   switch (refiner) {
6562   case 3:
6563     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6564     cMax = PetscMin(cEnd, cMax);
6565     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6566     fMax = PetscMin(fEnd, fMax);
6567   }
6568   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6569   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6570   /* Caculate size of new SF */
6571   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6572   if (numRoots < 0) PetscFunctionReturn(0);
6573   for (l = 0; l < numLeaves; ++l) {
6574     const PetscInt p = localPoints[l];
6575 
6576     switch (refiner) {
6577     case 1:
6578       /* Simplicial 2D */
6579       if ((p >= vStart) && (p < vEnd)) {
6580         /* Old vertices stay the same */
6581         ++numLeavesNew;
6582       } else if ((p >= fStart) && (p < fEnd)) {
6583         /* Old faces add new faces and vertex */
6584         numLeavesNew += 1 + 2;
6585       } else if ((p >= cStart) && (p < cEnd)) {
6586         /* Old cells add new cells and interior faces */
6587         numLeavesNew += 4 + 3;
6588       }
6589       break;
6590     case 2:
6591       /* Hex 2D */
6592       if ((p >= vStart) && (p < vEnd)) {
6593         /* Old vertices stay the same */
6594         ++numLeavesNew;
6595       } else if ((p >= fStart) && (p < fEnd)) {
6596         /* Old faces add new faces and vertex */
6597         numLeavesNew += 1 + 2;
6598       } else if ((p >= cStart) && (p < cEnd)) {
6599         /* Old cells add new cells and interior faces */
6600         numLeavesNew += 4 + 4;
6601       }
6602       break;
6603     default:
6604       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6605     }
6606   }
6607   /* Communicate depthSizes for each remote rank */
6608   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6609   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6610   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6611   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);
6612   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6613   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6614   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6615   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6616   for (n = 0; n < numNeighbors; ++n) {
6617     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6618   }
6619   depthSizeOld[depth]   = cMax;
6620   depthSizeOld[0]       = vMax;
6621   depthSizeOld[depth-1] = fMax;
6622   depthSizeOld[1]       = eMax;
6623 
6624   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6625   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6626 
6627   depthSizeOld[depth]   = cEnd - cStart;
6628   depthSizeOld[0]       = vEnd - vStart;
6629   depthSizeOld[depth-1] = fEnd - fStart;
6630   depthSizeOld[1]       = eEnd - eStart;
6631 
6632   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6633   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6634   for (n = 0; n < numNeighbors; ++n) {
6635     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6636   }
6637   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6638   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6639   /* Calculate new point SF */
6640   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6641   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6642   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6643   for (l = 0, m = 0; l < numLeaves; ++l) {
6644     PetscInt    p     = localPoints[l];
6645     PetscInt    rp    = remotePoints[l].index, n;
6646     PetscMPIInt rrank = remotePoints[l].rank;
6647 
6648     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6649     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6650     switch (refiner) {
6651     case 1:
6652       /* Simplicial 2D */
6653       if ((p >= vStart) && (p < vEnd)) {
6654         /* Old vertices stay the same */
6655         localPointsNew[m]        = vStartNew     + (p  - vStart);
6656         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6657         remotePointsNew[m].rank  = rrank;
6658         ++m;
6659       } else if ((p >= fStart) && (p < fEnd)) {
6660         /* Old faces add new faces and vertex */
6661         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6662         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6663         remotePointsNew[m].rank  = rrank;
6664         ++m;
6665         for (r = 0; r < 2; ++r, ++m) {
6666           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6667           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6668           remotePointsNew[m].rank  = rrank;
6669         }
6670       } else if ((p >= cStart) && (p < cEnd)) {
6671         /* Old cells add new cells and interior faces */
6672         for (r = 0; r < 4; ++r, ++m) {
6673           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6674           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6675           remotePointsNew[m].rank  = rrank;
6676         }
6677         for (r = 0; r < 3; ++r, ++m) {
6678           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6679           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6680           remotePointsNew[m].rank  = rrank;
6681         }
6682       }
6683       break;
6684     case 2:
6685       /* Hex 2D */
6686       if ((p >= vStart) && (p < vEnd)) {
6687         /* Old vertices stay the same */
6688         localPointsNew[m]        = vStartNew     + (p  - vStart);
6689         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6690         remotePointsNew[m].rank  = rrank;
6691         ++m;
6692       } else if ((p >= fStart) && (p < fEnd)) {
6693         /* Old faces add new faces and vertex */
6694         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6695         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6696         remotePointsNew[m].rank  = rrank;
6697         ++m;
6698         for (r = 0; r < 2; ++r, ++m) {
6699           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6700           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6701           remotePointsNew[m].rank  = rrank;
6702         }
6703       } else if ((p >= cStart) && (p < cEnd)) {
6704         /* Old cells add new cells and interior faces */
6705         for (r = 0; r < 4; ++r, ++m) {
6706           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6707           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6708           remotePointsNew[m].rank  = rrank;
6709         }
6710         for (r = 0; r < 4; ++r, ++m) {
6711           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6712           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6713           remotePointsNew[m].rank  = rrank;
6714         }
6715       }
6716       break;
6717     case 3:
6718       /* Hybrid simplicial 2D */
6719       if ((p >= vStart) && (p < vEnd)) {
6720         /* Old vertices stay the same */
6721         localPointsNew[m]        = vStartNew     + (p  - vStart);
6722         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6723         remotePointsNew[m].rank  = rrank;
6724         ++m;
6725       } else if ((p >= fStart) && (p < fMax)) {
6726         /* Old interior faces add new faces and vertex */
6727         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6728         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6729         remotePointsNew[m].rank  = rrank;
6730         ++m;
6731         for (r = 0; r < 2; ++r, ++m) {
6732           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6733           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6734           remotePointsNew[m].rank  = rrank;
6735         }
6736       } else if ((p >= fMax) && (p < fEnd)) {
6737         /* Old hybrid faces stay the same */
6738         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6739         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6740         remotePointsNew[m].rank  = rrank;
6741         ++m;
6742       } else if ((p >= cStart) && (p < cMax)) {
6743         /* Old interior cells add new cells and interior faces */
6744         for (r = 0; r < 4; ++r, ++m) {
6745           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6746           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6747           remotePointsNew[m].rank  = rrank;
6748         }
6749         for (r = 0; r < 3; ++r, ++m) {
6750           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6751           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6752           remotePointsNew[m].rank  = rrank;
6753         }
6754       } else if ((p >= cStart) && (p < cMax)) {
6755         /* Old hybrid cells add new cells and hybrid face */
6756         for (r = 0; r < 2; ++r, ++m) {
6757           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6758           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6759           remotePointsNew[m].rank  = rrank;
6760         }
6761         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6762         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]);
6763         remotePointsNew[m].rank  = rrank;
6764         ++m;
6765       }
6766       break;
6767     default:
6768       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6769     }
6770   }
6771   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6772   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6773   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6774   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6775   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6776   PetscFunctionReturn(0);
6777 }
6778 
6779 #undef __FUNCT__
6780 #define __FUNCT__ "CellRefinerCreateLabels"
6781 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6782 {
6783   PetscInt       numLabels, l;
6784   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
6785   PetscErrorCode ierr;
6786 
6787   PetscFunctionBegin;
6788   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6789   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6790   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6791   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6792 
6793   cStartNew = 0;
6794   vStartNew = depthSize[2];
6795   fStartNew = depthSize[2] + depthSize[0];
6796 
6797   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6798   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6799   switch (refiner) {
6800   case 3:
6801     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6802     cMax = PetscMin(cEnd, cMax);
6803     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6804     fMax = PetscMin(fEnd, fMax);
6805   }
6806   for (l = 0; l < numLabels; ++l) {
6807     DMLabel         label, labelNew;
6808     const char     *lname;
6809     PetscBool       isDepth;
6810     IS              valueIS;
6811     const PetscInt *values;
6812     PetscInt        numValues, val;
6813 
6814     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6815     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6816     if (isDepth) continue;
6817     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6818     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6819     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6820     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6821     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6822     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6823     for (val = 0; val < numValues; ++val) {
6824       IS              pointIS;
6825       const PetscInt *points;
6826       PetscInt        numPoints, n;
6827 
6828       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6829       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6830       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6831       for (n = 0; n < numPoints; ++n) {
6832         const PetscInt p = points[n];
6833         switch (refiner) {
6834         case 1:
6835           /* Simplicial 2D */
6836           if ((p >= vStart) && (p < vEnd)) {
6837             /* Old vertices stay the same */
6838             newp = vStartNew + (p - vStart);
6839             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6840           } else if ((p >= fStart) && (p < fEnd)) {
6841             /* Old faces add new faces and vertex */
6842             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6843             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6844             for (r = 0; r < 2; ++r) {
6845               newp = fStartNew + (p - fStart)*2 + r;
6846               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6847             }
6848           } else if ((p >= cStart) && (p < cEnd)) {
6849             /* Old cells add new cells and interior faces */
6850             for (r = 0; r < 4; ++r) {
6851               newp = cStartNew + (p - cStart)*4 + r;
6852               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6853             }
6854             for (r = 0; r < 3; ++r) {
6855               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6856               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6857             }
6858           }
6859           break;
6860         case 2:
6861           /* Hex 2D */
6862           if ((p >= vStart) && (p < vEnd)) {
6863             /* Old vertices stay the same */
6864             newp = vStartNew + (p - vStart);
6865             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6866           } else if ((p >= fStart) && (p < fEnd)) {
6867             /* Old faces add new faces and vertex */
6868             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6869             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6870             for (r = 0; r < 2; ++r) {
6871               newp = fStartNew + (p - fStart)*2 + r;
6872               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6873             }
6874           } else if ((p >= cStart) && (p < cEnd)) {
6875             /* Old cells add new cells and interior faces and vertex */
6876             for (r = 0; r < 4; ++r) {
6877               newp = cStartNew + (p - cStart)*4 + r;
6878               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6879             }
6880             for (r = 0; r < 4; ++r) {
6881               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6882               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6883             }
6884             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6885             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6886           }
6887           break;
6888         case 3:
6889           /* Hybrid simplicial 2D */
6890           if ((p >= vStart) && (p < vEnd)) {
6891             /* Old vertices stay the same */
6892             newp = vStartNew + (p - vStart);
6893             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6894           } else if ((p >= fStart) && (p < fMax)) {
6895             /* Old interior faces add new faces and vertex */
6896             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6897             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6898             for (r = 0; r < 2; ++r) {
6899               newp = fStartNew + (p - fStart)*2 + r;
6900               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6901             }
6902           } else if ((p >= fMax) && (p < fEnd)) {
6903             /* Old hybrid faces stay the same */
6904             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6905             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6906           } else if ((p >= cStart) && (p < cMax)) {
6907             /* Old interior cells add new cells and interior faces */
6908             for (r = 0; r < 4; ++r) {
6909               newp = cStartNew + (p - cStart)*4 + r;
6910               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6911             }
6912             for (r = 0; r < 3; ++r) {
6913               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6914               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6915             }
6916           } else if ((p >= cMax) && (p < cEnd)) {
6917             /* Old hybrid cells add new cells and hybrid face */
6918             for (r = 0; r < 2; ++r) {
6919               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6920               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6921             }
6922             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6923             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6924           }
6925           break;
6926         default:
6927           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6928         }
6929       }
6930       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6931       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6932     }
6933     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6934     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6935     if (0) {
6936       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6937       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6938       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6939     }
6940   }
6941   PetscFunctionReturn(0);
6942 }
6943 
6944 #undef __FUNCT__
6945 #define __FUNCT__ "DMPlexRefine_Uniform"
6946 /* This will only work for interpolated meshes */
6947 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6948 {
6949   DM             rdm;
6950   PetscInt      *depthSize;
6951   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6952   PetscErrorCode ierr;
6953 
6954   PetscFunctionBegin;
6955   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6956   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6957   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6958   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6959   /* Calculate number of new points of each depth */
6960   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6961   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
6962   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6963   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6964   /* Step 1: Set chart */
6965   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6966   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6967   /* Step 2: Set cone/support sizes */
6968   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6969   /* Step 3: Setup refined DM */
6970   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6971   /* Step 4: Set cones and supports */
6972   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6973   /* Step 5: Stratify */
6974   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6975   /* Step 6: Set coordinates for vertices */
6976   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6977   /* Step 7: Create pointSF */
6978   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6979   /* Step 8: Create labels */
6980   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6981   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6982 
6983   *dmRefined = rdm;
6984   PetscFunctionReturn(0);
6985 }
6986 
6987 #undef __FUNCT__
6988 #define __FUNCT__ "DMPlexSetRefinementUniform"
6989 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6990 {
6991   DM_Plex *mesh = (DM_Plex*) dm->data;
6992 
6993   PetscFunctionBegin;
6994   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6995   mesh->refinementUniform = refinementUniform;
6996   PetscFunctionReturn(0);
6997 }
6998 
6999 #undef __FUNCT__
7000 #define __FUNCT__ "DMPlexGetRefinementUniform"
7001 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7002 {
7003   DM_Plex *mesh = (DM_Plex*) dm->data;
7004 
7005   PetscFunctionBegin;
7006   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7007   PetscValidPointer(refinementUniform,  2);
7008   *refinementUniform = mesh->refinementUniform;
7009   PetscFunctionReturn(0);
7010 }
7011 
7012 #undef __FUNCT__
7013 #define __FUNCT__ "DMPlexSetRefinementLimit"
7014 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7015 {
7016   DM_Plex *mesh = (DM_Plex*) dm->data;
7017 
7018   PetscFunctionBegin;
7019   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7020   mesh->refinementLimit = refinementLimit;
7021   PetscFunctionReturn(0);
7022 }
7023 
7024 #undef __FUNCT__
7025 #define __FUNCT__ "DMPlexGetRefinementLimit"
7026 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7027 {
7028   DM_Plex *mesh = (DM_Plex*) dm->data;
7029 
7030   PetscFunctionBegin;
7031   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7032   PetscValidPointer(refinementLimit,  2);
7033   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7034   *refinementLimit = mesh->refinementLimit;
7035   PetscFunctionReturn(0);
7036 }
7037 
7038 #undef __FUNCT__
7039 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7040 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7041 {
7042   PetscInt       dim, cStart, coneSize, cMax;
7043   PetscErrorCode ierr;
7044 
7045   PetscFunctionBegin;
7046   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7047   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7048   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7049   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7050   switch (dim) {
7051   case 2:
7052     switch (coneSize) {
7053     case 3:
7054       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7055       else *cellRefiner = 1; /* Triangular */
7056       break;
7057     case 4:
7058       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7059       else *cellRefiner = 2; /* Quadrilateral */
7060       break;
7061     default:
7062       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7063     }
7064     break;
7065   default:
7066     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7067   }
7068   PetscFunctionReturn(0);
7069 }
7070 
7071 #undef __FUNCT__
7072 #define __FUNCT__ "DMRefine_Plex"
7073 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7074 {
7075   PetscReal      refinementLimit;
7076   PetscInt       dim, cStart, cEnd;
7077   char           genname[1024], *name = NULL;
7078   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7079   PetscErrorCode ierr;
7080 
7081   PetscFunctionBegin;
7082   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7083   if (isUniform) {
7084     CellRefiner cellRefiner;
7085 
7086     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7087     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7088     PetscFunctionReturn(0);
7089   }
7090   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7091   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7092   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7093   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7094   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7095   if (flg) name = genname;
7096   if (name) {
7097     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7098     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7099     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7100   }
7101   switch (dim) {
7102   case 2:
7103     if (!name || isTriangle) {
7104 #if defined(PETSC_HAVE_TRIANGLE)
7105       double  *maxVolumes;
7106       PetscInt c;
7107 
7108       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7109       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7110       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7111 #else
7112       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7113 #endif
7114     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7115     break;
7116   case 3:
7117     if (!name || isCTetgen) {
7118 #if defined(PETSC_HAVE_CTETGEN)
7119       PetscReal *maxVolumes;
7120       PetscInt   c;
7121 
7122       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7123       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7124       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7125 #else
7126       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7127 #endif
7128     } else if (isTetgen) {
7129 #if defined(PETSC_HAVE_TETGEN)
7130       double  *maxVolumes;
7131       PetscInt c;
7132 
7133       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7134       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7135       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7136 #else
7137       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7138 #endif
7139     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7140     break;
7141   default:
7142     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7143   }
7144   PetscFunctionReturn(0);
7145 }
7146 
7147 #undef __FUNCT__
7148 #define __FUNCT__ "DMPlexGetDepth"
7149 /*@
7150   DMPlexGetDepth - get the number of strata
7151 
7152   Not Collective
7153 
7154   Input Parameters:
7155 . dm           - The DMPlex object
7156 
7157   Output Parameters:
7158 . depth - number of strata
7159 
7160   Level: developer
7161 
7162   Notes:
7163   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7164 
7165 .keywords: mesh, points
7166 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7167 @*/
7168 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7169 {
7170   PetscInt       d;
7171   PetscErrorCode ierr;
7172 
7173   PetscFunctionBegin;
7174   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7175   PetscValidPointer(depth, 2);
7176   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7177   *depth = d-1;
7178   PetscFunctionReturn(0);
7179 }
7180 
7181 #undef __FUNCT__
7182 #define __FUNCT__ "DMPlexGetDepthStratum"
7183 /*@
7184   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7185 
7186   Not Collective
7187 
7188   Input Parameters:
7189 + dm           - The DMPlex object
7190 - stratumValue - The requested depth
7191 
7192   Output Parameters:
7193 + start - The first point at this depth
7194 - end   - One beyond the last point at this depth
7195 
7196   Level: developer
7197 
7198 .keywords: mesh, points
7199 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7200 @*/
7201 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7202 {
7203   DM_Plex       *mesh = (DM_Plex*) dm->data;
7204   DMLabel        next  = mesh->labels;
7205   PetscBool      flg   = PETSC_FALSE;
7206   PetscInt       depth;
7207   PetscErrorCode ierr;
7208 
7209   PetscFunctionBegin;
7210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7211   if (stratumValue < 0) {
7212     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7213     PetscFunctionReturn(0);
7214   } else {
7215     PetscInt pStart, pEnd;
7216 
7217     if (start) *start = 0;
7218     if (end)   *end   = 0;
7219     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7220     if (pStart == pEnd) PetscFunctionReturn(0);
7221   }
7222   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7223   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7224   /* We should have a generic GetLabel() and a Label class */
7225   while (next) {
7226     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7227     if (flg) break;
7228     next = next->next;
7229   }
7230   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7231   depth = stratumValue;
7232   if ((depth < 0) || (depth >= next->numStrata)) {
7233     if (start) *start = 0;
7234     if (end)   *end   = 0;
7235   } else {
7236     if (start) *start = next->points[next->stratumOffsets[depth]];
7237     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7238   }
7239   PetscFunctionReturn(0);
7240 }
7241 
7242 #undef __FUNCT__
7243 #define __FUNCT__ "DMPlexGetHeightStratum"
7244 /*@
7245   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7246 
7247   Not Collective
7248 
7249   Input Parameters:
7250 + dm           - The DMPlex object
7251 - stratumValue - The requested height
7252 
7253   Output Parameters:
7254 + start - The first point at this height
7255 - end   - One beyond the last point at this height
7256 
7257   Level: developer
7258 
7259 .keywords: mesh, points
7260 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7261 @*/
7262 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7263 {
7264   DM_Plex       *mesh = (DM_Plex*) dm->data;
7265   DMLabel        next  = mesh->labels;
7266   PetscBool      flg   = PETSC_FALSE;
7267   PetscInt       depth;
7268   PetscErrorCode ierr;
7269 
7270   PetscFunctionBegin;
7271   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7272   if (stratumValue < 0) {
7273     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7274   } else {
7275     PetscInt pStart, pEnd;
7276 
7277     if (start) *start = 0;
7278     if (end)   *end   = 0;
7279     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7280     if (pStart == pEnd) PetscFunctionReturn(0);
7281   }
7282   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7283   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7284   /* We should have a generic GetLabel() and a Label class */
7285   while (next) {
7286     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7287     if (flg) break;
7288     next = next->next;
7289   }
7290   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7291   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7292   if ((depth < 0) || (depth >= next->numStrata)) {
7293     if (start) *start = 0;
7294     if (end)   *end   = 0;
7295   } else {
7296     if (start) *start = next->points[next->stratumOffsets[depth]];
7297     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7298   }
7299   PetscFunctionReturn(0);
7300 }
7301 
7302 #undef __FUNCT__
7303 #define __FUNCT__ "DMPlexCreateSectionInitial"
7304 /* Set the number of dof on each point and separate by fields */
7305 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7306 {
7307   PetscInt      *numDofTot;
7308   PetscInt       pStart = 0, pEnd = 0;
7309   PetscInt       p, d, f;
7310   PetscErrorCode ierr;
7311 
7312   PetscFunctionBegin;
7313   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7314   for (d = 0; d <= dim; ++d) {
7315     numDofTot[d] = 0;
7316     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7317   }
7318   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
7319   if (numFields > 0) {
7320     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7321     if (numComp) {
7322       for (f = 0; f < numFields; ++f) {
7323         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7324       }
7325     }
7326   }
7327   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7328   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7329   for (d = 0; d <= dim; ++d) {
7330     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7331     for (p = pStart; p < pEnd; ++p) {
7332       for (f = 0; f < numFields; ++f) {
7333         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7334       }
7335       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7336     }
7337   }
7338   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7339   PetscFunctionReturn(0);
7340 }
7341 
7342 #undef __FUNCT__
7343 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7344 /* Set the number of dof on each point and separate by fields
7345    If constDof is PETSC_DETERMINE, constrain every dof on the point
7346 */
7347 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7348 {
7349   PetscInt       numFields;
7350   PetscInt       bc;
7351   PetscErrorCode ierr;
7352 
7353   PetscFunctionBegin;
7354   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7355   for (bc = 0; bc < numBC; ++bc) {
7356     PetscInt        field = 0;
7357     const PetscInt *idx;
7358     PetscInt        n, i;
7359 
7360     if (numFields) field = bcField[bc];
7361     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7362     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7363     for (i = 0; i < n; ++i) {
7364       const PetscInt p        = idx[i];
7365       PetscInt       numConst = constDof;
7366 
7367       /* Constrain every dof on the point */
7368       if (numConst < 0) {
7369         if (numFields) {
7370           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7371         } else {
7372           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7373         }
7374       }
7375       if (numFields) {
7376         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7377       }
7378       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7379     }
7380     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7381   }
7382   PetscFunctionReturn(0);
7383 }
7384 
7385 #undef __FUNCT__
7386 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7387 /* Set the constrained indices on each point and separate by fields */
7388 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7389 {
7390   PetscInt      *maxConstraints;
7391   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7392   PetscErrorCode ierr;
7393 
7394   PetscFunctionBegin;
7395   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7396   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7397   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7398   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7399   for (p = pStart; p < pEnd; ++p) {
7400     PetscInt cdof;
7401 
7402     if (numFields) {
7403       for (f = 0; f < numFields; ++f) {
7404         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7405         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7406       }
7407     } else {
7408       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7409       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7410     }
7411   }
7412   for (f = 0; f < numFields; ++f) {
7413     maxConstraints[numFields] += maxConstraints[f];
7414   }
7415   if (maxConstraints[numFields]) {
7416     PetscInt *indices;
7417 
7418     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7419     for (p = pStart; p < pEnd; ++p) {
7420       PetscInt cdof, d;
7421 
7422       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7423       if (cdof) {
7424         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7425         if (numFields) {
7426           PetscInt numConst = 0, foff = 0;
7427 
7428           for (f = 0; f < numFields; ++f) {
7429             PetscInt cfdof, fdof;
7430 
7431             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7432             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7433             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7434             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7435             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7436             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7437             numConst += cfdof;
7438             foff     += fdof;
7439           }
7440           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7441         } else {
7442           for (d = 0; d < cdof; ++d) indices[d] = d;
7443         }
7444         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7445       }
7446     }
7447     ierr = PetscFree(indices);CHKERRQ(ierr);
7448   }
7449   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7450   PetscFunctionReturn(0);
7451 }
7452 
7453 #undef __FUNCT__
7454 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7455 /* Set the constrained field indices on each point */
7456 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7457 {
7458   const PetscInt *points, *indices;
7459   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7460   PetscErrorCode  ierr;
7461 
7462   PetscFunctionBegin;
7463   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7464   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7465 
7466   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7467   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7468   if (!constraintIndices) {
7469     PetscInt *idx, i;
7470 
7471     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7472     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7473     for (i = 0; i < maxDof; ++i) idx[i] = i;
7474     for (p = 0; p < numPoints; ++p) {
7475       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7476     }
7477     ierr = PetscFree(idx);CHKERRQ(ierr);
7478   } else {
7479     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7480     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7481     for (p = 0; p < numPoints; ++p) {
7482       PetscInt fcdof;
7483 
7484       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7485       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);
7486       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7487     }
7488     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7489   }
7490   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7491   PetscFunctionReturn(0);
7492 }
7493 
7494 #undef __FUNCT__
7495 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7496 /* Set the constrained indices on each point and separate by fields */
7497 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7498 {
7499   PetscInt      *indices;
7500   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7501   PetscErrorCode ierr;
7502 
7503   PetscFunctionBegin;
7504   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7505   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7506   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7507   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7508   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7509   for (p = pStart; p < pEnd; ++p) {
7510     PetscInt cdof, d;
7511 
7512     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7513     if (cdof) {
7514       PetscInt numConst = 0, foff = 0;
7515 
7516       for (f = 0; f < numFields; ++f) {
7517         const PetscInt *fcind;
7518         PetscInt        fdof, fcdof;
7519 
7520         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7521         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7522         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7523         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7524         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
7525         foff     += fdof;
7526         numConst += fcdof;
7527       }
7528       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7529       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7530     }
7531   }
7532   ierr = PetscFree(indices);CHKERRQ(ierr);
7533   PetscFunctionReturn(0);
7534 }
7535 
7536 #undef __FUNCT__
7537 #define __FUNCT__ "DMPlexCreateSection"
7538 /*@C
7539   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7540 
7541   Not Collective
7542 
7543   Input Parameters:
7544 + dm        - The DMPlex object
7545 . dim       - The spatial dimension of the problem
7546 . numFields - The number of fields in the problem
7547 . numComp   - An array of size numFields that holds the number of components for each field
7548 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7549 . numBC     - The number of boundary conditions
7550 . bcField   - An array of size numBC giving the field number for each boundry condition
7551 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7552 
7553   Output Parameter:
7554 . section - The PetscSection object
7555 
7556   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
7557   nubmer of dof for field 0 on each edge.
7558 
7559   Level: developer
7560 
7561 .keywords: mesh, elements
7562 .seealso: DMPlexCreate(), PetscSectionCreate()
7563 @*/
7564 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
7565 {
7566   PetscErrorCode ierr;
7567 
7568   PetscFunctionBegin;
7569   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7570   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7571   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7572   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7573   {
7574     PetscBool view = PETSC_FALSE;
7575 
7576     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7577     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7578   }
7579   PetscFunctionReturn(0);
7580 }
7581 
7582 #undef __FUNCT__
7583 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7584 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
7585 {
7586   PetscSection   section;
7587   PetscErrorCode ierr;
7588 
7589   PetscFunctionBegin;
7590   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7591   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7592   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7593   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7594   PetscFunctionReturn(0);
7595 }
7596 
7597 #undef __FUNCT__
7598 #define __FUNCT__ "DMPlexGetCoordinateSection"
7599 /*@
7600   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7601 
7602   Not Collective
7603 
7604   Input Parameter:
7605 . dm - The DMPlex object
7606 
7607   Output Parameter:
7608 . section - The PetscSection object
7609 
7610   Level: intermediate
7611 
7612 .keywords: mesh, coordinates
7613 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7614 @*/
7615 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
7616 {
7617   DM             cdm;
7618   PetscErrorCode ierr;
7619 
7620   PetscFunctionBegin;
7621   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7622   PetscValidPointer(section, 2);
7623   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7624   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7625   PetscFunctionReturn(0);
7626 }
7627 
7628 #undef __FUNCT__
7629 #define __FUNCT__ "DMPlexSetCoordinateSection"
7630 /*@
7631   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7632 
7633   Not Collective
7634 
7635   Input Parameters:
7636 + dm      - The DMPlex object
7637 - section - The PetscSection object
7638 
7639   Level: intermediate
7640 
7641 .keywords: mesh, coordinates
7642 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7643 @*/
7644 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
7645 {
7646   DM             cdm;
7647   PetscErrorCode ierr;
7648 
7649   PetscFunctionBegin;
7650   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7651   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
7652   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7653   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7654   PetscFunctionReturn(0);
7655 }
7656 
7657 #undef __FUNCT__
7658 #define __FUNCT__ "DMPlexGetConeSection"
7659 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
7660 {
7661   DM_Plex *mesh = (DM_Plex*) dm->data;
7662 
7663   PetscFunctionBegin;
7664   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7665   if (section) *section = mesh->coneSection;
7666   PetscFunctionReturn(0);
7667 }
7668 
7669 #undef __FUNCT__
7670 #define __FUNCT__ "DMPlexGetCones"
7671 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
7672 {
7673   DM_Plex *mesh = (DM_Plex*) dm->data;
7674 
7675   PetscFunctionBegin;
7676   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7677   if (cones) *cones = mesh->cones;
7678   PetscFunctionReturn(0);
7679 }
7680 
7681 #undef __FUNCT__
7682 #define __FUNCT__ "DMPlexGetConeOrientations"
7683 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
7684 {
7685   DM_Plex *mesh = (DM_Plex*) dm->data;
7686 
7687   PetscFunctionBegin;
7688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7689   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7690   PetscFunctionReturn(0);
7691 }
7692 
7693 #undef __FUNCT__
7694 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7695 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7696 {
7697   const PetscInt embedDim = 2;
7698   PetscReal      x        = PetscRealPart(point[0]);
7699   PetscReal      y        = PetscRealPart(point[1]);
7700   PetscReal      v0[2], J[4], invJ[4], detJ;
7701   PetscReal      xi, eta;
7702   PetscErrorCode ierr;
7703 
7704   PetscFunctionBegin;
7705   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7706   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7707   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7708 
7709   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
7710   else *cell = -1;
7711   PetscFunctionReturn(0);
7712 }
7713 
7714 #undef __FUNCT__
7715 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7716 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7717 {
7718   PetscSection       coordSection;
7719   Vec                coordsLocal;
7720   const PetscScalar *coords;
7721   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7722   PetscReal          x         = PetscRealPart(point[0]);
7723   PetscReal          y         = PetscRealPart(point[1]);
7724   PetscInt           crossings = 0, f;
7725   PetscErrorCode     ierr;
7726 
7727   PetscFunctionBegin;
7728   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7729   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7730   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7731   for (f = 0; f < 4; ++f) {
7732     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7733     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7734     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7735     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7736     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7737     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7738     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7739     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7740     if ((cond1 || cond2)  && above) ++crossings;
7741   }
7742   if (crossings % 2) *cell = c;
7743   else *cell = -1;
7744   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7745   PetscFunctionReturn(0);
7746 }
7747 
7748 #undef __FUNCT__
7749 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7750 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7751 {
7752   const PetscInt embedDim = 3;
7753   PetscReal      v0[3], J[9], invJ[9], detJ;
7754   PetscReal      x = PetscRealPart(point[0]);
7755   PetscReal      y = PetscRealPart(point[1]);
7756   PetscReal      z = PetscRealPart(point[2]);
7757   PetscReal      xi, eta, zeta;
7758   PetscErrorCode ierr;
7759 
7760   PetscFunctionBegin;
7761   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7762   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
7763   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
7764   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
7765 
7766   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
7767   else *cell = -1;
7768   PetscFunctionReturn(0);
7769 }
7770 
7771 #undef __FUNCT__
7772 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7773 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7774 {
7775   PetscSection       coordSection;
7776   Vec                coordsLocal;
7777   const PetscScalar *coords;
7778   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7779                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7780   PetscBool          found = PETSC_TRUE;
7781   PetscInt           f;
7782   PetscErrorCode     ierr;
7783 
7784   PetscFunctionBegin;
7785   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7786   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7787   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7788   for (f = 0; f < 6; ++f) {
7789     /* Check the point is under plane */
7790     /*   Get face normal */
7791     PetscReal v_i[3];
7792     PetscReal v_j[3];
7793     PetscReal normal[3];
7794     PetscReal pp[3];
7795     PetscReal dot;
7796 
7797     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
7798     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
7799     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
7800     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
7801     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
7802     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
7803     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
7804     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
7805     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
7806     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
7807     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
7808     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
7809     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7810 
7811     /* Check that projected point is in face (2D location problem) */
7812     if (dot < 0.0) {
7813       found = PETSC_FALSE;
7814       break;
7815     }
7816   }
7817   if (found) *cell = c;
7818   else *cell = -1;
7819   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7820   PetscFunctionReturn(0);
7821 }
7822 
7823 #undef __FUNCT__
7824 #define __FUNCT__ "DMLocatePoints_Plex"
7825 /*
7826  Need to implement using the guess
7827 */
7828 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7829 {
7830   PetscInt       cell = -1 /*, guess = -1*/;
7831   PetscInt       bs, numPoints, p;
7832   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7833   PetscInt      *cells;
7834   PetscScalar   *a;
7835   PetscErrorCode ierr;
7836 
7837   PetscFunctionBegin;
7838   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7839   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7840   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7841   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7842   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7843   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7844   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7845   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);
7846   numPoints /= bs;
7847   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7848   for (p = 0; p < numPoints; ++p) {
7849     const PetscScalar *point = &a[p*bs];
7850 
7851     switch (dim) {
7852     case 2:
7853       for (c = cStart; c < cEnd; ++c) {
7854         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7855         switch (coneSize) {
7856         case 3:
7857           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7858           break;
7859         case 4:
7860           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7861           break;
7862         default:
7863           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7864         }
7865         if (cell >= 0) break;
7866       }
7867       break;
7868     case 3:
7869       for (c = cStart; c < cEnd; ++c) {
7870         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7871         switch (coneSize) {
7872         case 4:
7873           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
7874           break;
7875         case 8:
7876           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
7877           break;
7878         default:
7879           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7880         }
7881         if (cell >= 0) break;
7882       }
7883       break;
7884     default:
7885       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
7886     }
7887     cells[p] = cell;
7888   }
7889   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
7890   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
7891   PetscFunctionReturn(0);
7892 }
7893 
7894 /******************************** FEM Support **********************************/
7895 
7896 #undef __FUNCT__
7897 #define __FUNCT__ "DMPlexVecGetClosure"
7898 /*@C
7899   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
7900 
7901   Not collective
7902 
7903   Input Parameters:
7904 + dm - The DM
7905 . section - The section describing the layout in v, or NULL to use the default section
7906 . v - The local vector
7907 - point - The sieve point in the DM
7908 
7909   Output Parameters:
7910 + csize - The number of values in the closure, or NULL
7911 - values - The array of values, which is a borrowed array and should not be freed
7912 
7913   Level: intermediate
7914 
7915 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7916 @*/
7917 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
7918 {
7919   PetscScalar   *array, *vArray;
7920   PetscInt      *points = NULL;
7921   PetscInt       offsets[32];
7922   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
7923   PetscErrorCode ierr;
7924 
7925   PetscFunctionBegin;
7926   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7927   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7928   if (!section) {
7929     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7930   }
7931   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7932   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7933   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7934   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7935   /* Compress out points not in the section */
7936   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7937   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7938     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7939       points[q*2]   = points[p];
7940       points[q*2+1] = points[p+1];
7941       ++q;
7942     }
7943   }
7944   numPoints = q;
7945   for (p = 0, size = 0; p < numPoints*2; p += 2) {
7946     PetscInt dof, fdof;
7947 
7948     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7949     for (f = 0; f < numFields; ++f) {
7950       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7951       offsets[f+1] += fdof;
7952     }
7953     size += dof;
7954   }
7955   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7956   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
7957   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
7958   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
7959   for (p = 0; p < numPoints*2; p += 2) {
7960     PetscInt     o = points[p+1];
7961     PetscInt     dof, off, d;
7962     PetscScalar *varr;
7963 
7964     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7965     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
7966     varr = &vArray[off];
7967     if (numFields) {
7968       PetscInt fdof, foff, fcomp, f, c;
7969 
7970       for (f = 0, foff = 0; f < numFields; ++f) {
7971         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7972         if (o >= 0) {
7973           for (d = 0; d < fdof; ++d, ++offsets[f]) {
7974             array[offsets[f]] = varr[foff+d];
7975           }
7976         } else {
7977           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7978           for (d = fdof/fcomp-1; d >= 0; --d) {
7979             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
7980               array[offsets[f]] = varr[foff+d*fcomp+c];
7981             }
7982           }
7983         }
7984         foff += fdof;
7985       }
7986     } else {
7987       if (o >= 0) {
7988         for (d = 0; d < dof; ++d, ++offsets[0]) {
7989           array[offsets[0]] = varr[d];
7990         }
7991       } else {
7992         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
7993           array[offsets[0]] = varr[d];
7994         }
7995       }
7996     }
7997   }
7998   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7999   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8000   if (csize) *csize = size;
8001   *values = array;
8002   PetscFunctionReturn(0);
8003 }
8004 
8005 #undef __FUNCT__
8006 #define __FUNCT__ "DMPlexVecRestoreClosure"
8007 /*@C
8008   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8009 
8010   Not collective
8011 
8012   Input Parameters:
8013 + dm - The DM
8014 . section - The section describing the layout in v, or NULL to use the default section
8015 . v - The local vector
8016 . point - The sieve point in the DM
8017 . csize - The number of values in the closure, or NULL
8018 - values - The array of values, which is a borrowed array and should not be freed
8019 
8020   Level: intermediate
8021 
8022 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8023 @*/
8024 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8025 {
8026   PetscInt       size = 0;
8027   PetscErrorCode ierr;
8028 
8029   PetscFunctionBegin;
8030   /* Should work without recalculating size */
8031   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8032   PetscFunctionReturn(0);
8033 }
8034 
8035 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8036 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8037 
8038 #undef __FUNCT__
8039 #define __FUNCT__ "updatePoint_private"
8040 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8041 {
8042   PetscInt        cdof;   /* The number of constraints on this point */
8043   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8044   PetscScalar    *a;
8045   PetscInt        off, cind = 0, k;
8046   PetscErrorCode  ierr;
8047 
8048   PetscFunctionBegin;
8049   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8050   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8051   a    = &array[off];
8052   if (!cdof || setBC) {
8053     if (orientation >= 0) {
8054       for (k = 0; k < dof; ++k) {
8055         fuse(&a[k], values[k]);
8056       }
8057     } else {
8058       for (k = 0; k < dof; ++k) {
8059         fuse(&a[k], values[dof-k-1]);
8060       }
8061     }
8062   } else {
8063     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8064     if (orientation >= 0) {
8065       for (k = 0; k < dof; ++k) {
8066         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8067         fuse(&a[k], values[k]);
8068       }
8069     } else {
8070       for (k = 0; k < dof; ++k) {
8071         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8072         fuse(&a[k], values[dof-k-1]);
8073       }
8074     }
8075   }
8076   PetscFunctionReturn(0);
8077 }
8078 
8079 #undef __FUNCT__
8080 #define __FUNCT__ "updatePointFields_private"
8081 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8082 {
8083   PetscScalar   *a;
8084   PetscInt       numFields, off, foff, f;
8085   PetscErrorCode ierr;
8086 
8087   PetscFunctionBegin;
8088   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8089   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8090   a    = &array[off];
8091   for (f = 0, foff = 0; f < numFields; ++f) {
8092     PetscInt        fdof, fcomp, fcdof;
8093     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8094     PetscInt        cind = 0, k, c;
8095 
8096     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8097     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8098     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8099     if (!fcdof || setBC) {
8100       if (orientation >= 0) {
8101         for (k = 0; k < fdof; ++k) {
8102           fuse(&a[foff+k], values[foffs[f]+k]);
8103         }
8104       } else {
8105         for (k = fdof/fcomp-1; k >= 0; --k) {
8106           for (c = 0; c < fcomp; ++c) {
8107             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8108           }
8109         }
8110       }
8111     } else {
8112       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8113       if (orientation >= 0) {
8114         for (k = 0; k < fdof; ++k) {
8115           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8116           fuse(&a[foff+k], values[foffs[f]+k]);
8117         }
8118       } else {
8119         for (k = fdof/fcomp-1; k >= 0; --k) {
8120           for (c = 0; c < fcomp; ++c) {
8121             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8122             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8123           }
8124         }
8125       }
8126     }
8127     foff     += fdof;
8128     foffs[f] += fdof;
8129   }
8130   PetscFunctionReturn(0);
8131 }
8132 
8133 #undef __FUNCT__
8134 #define __FUNCT__ "DMPlexVecSetClosure"
8135 /*@C
8136   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8137 
8138   Not collective
8139 
8140   Input Parameters:
8141 + dm - The DM
8142 . section - The section describing the layout in v, or NULL to use the default sectionw
8143 . v - The local vector
8144 . point - The sieve point in the DM
8145 . values - The array of values, which is a borrowed array and should not be freed
8146 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8147 
8148   Level: intermediate
8149 
8150 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8151 @*/
8152 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8153 {
8154   PetscScalar   *array;
8155   PetscInt      *points = NULL;
8156   PetscInt       offsets[32];
8157   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8158   PetscErrorCode ierr;
8159 
8160   PetscFunctionBegin;
8161   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8162   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8163   if (!section) {
8164     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8165   }
8166   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8167   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8168   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8169   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8170   /* Compress out points not in the section */
8171   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8172   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8173     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8174       points[q*2]   = points[p];
8175       points[q*2+1] = points[p+1];
8176       ++q;
8177     }
8178   }
8179   numPoints = q;
8180   for (p = 0; p < numPoints*2; p += 2) {
8181     PetscInt fdof;
8182 
8183     for (f = 0; f < numFields; ++f) {
8184       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8185       offsets[f+1] += fdof;
8186     }
8187   }
8188   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8189   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8190   if (numFields) {
8191     switch (mode) {
8192     case INSERT_VALUES:
8193       for (p = 0; p < numPoints*2; p += 2) {
8194         PetscInt o = points[p+1];
8195         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8196       } break;
8197     case INSERT_ALL_VALUES:
8198       for (p = 0; p < numPoints*2; p += 2) {
8199         PetscInt o = points[p+1];
8200         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8201       } break;
8202     case ADD_VALUES:
8203       for (p = 0; p < numPoints*2; p += 2) {
8204         PetscInt o = points[p+1];
8205         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8206       } break;
8207     case ADD_ALL_VALUES:
8208       for (p = 0; p < numPoints*2; p += 2) {
8209         PetscInt o = points[p+1];
8210         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8211       } break;
8212     default:
8213       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8214     }
8215   } else {
8216     switch (mode) {
8217     case INSERT_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_FALSE, o, &values[off], array);
8222       } break;
8223     case INSERT_ALL_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, insert, PETSC_TRUE,  o, &values[off], array);
8228       } break;
8229     case ADD_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_FALSE, o, &values[off], array);
8234       } break;
8235     case ADD_ALL_VALUES:
8236       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8237         PetscInt o = points[p+1];
8238         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8239         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8240       } break;
8241     default:
8242       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8243     }
8244   }
8245   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8246   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8247   PetscFunctionReturn(0);
8248 }
8249 
8250 #undef __FUNCT__
8251 #define __FUNCT__ "DMPlexPrintMatSetValues"
8252 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8253 {
8254   PetscMPIInt    rank;
8255   PetscInt       i, j;
8256   PetscErrorCode ierr;
8257 
8258   PetscFunctionBegin;
8259   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
8260   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8261   for (i = 0; i < numIndices; i++) {
8262     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8263   }
8264   for (i = 0; i < numIndices; i++) {
8265     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8266     for (j = 0; j < numIndices; j++) {
8267 #if defined(PETSC_USE_COMPLEX)
8268       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8269 #else
8270       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8271 #endif
8272     }
8273     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8274   }
8275   PetscFunctionReturn(0);
8276 }
8277 
8278 #undef __FUNCT__
8279 #define __FUNCT__ "indicesPoint_private"
8280 /* . off - The global offset of this point */
8281 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8282 {
8283   PetscInt        dof;    /* The number of unknowns on this point */
8284   PetscInt        cdof;   /* The number of constraints on this point */
8285   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8286   PetscInt        cind = 0, k;
8287   PetscErrorCode  ierr;
8288 
8289   PetscFunctionBegin;
8290   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8291   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8292   if (!cdof || setBC) {
8293     if (orientation >= 0) {
8294       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8295     } else {
8296       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8297     }
8298   } else {
8299     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8300     if (orientation >= 0) {
8301       for (k = 0; k < dof; ++k) {
8302         if ((cind < cdof) && (k == cdofs[cind])) {
8303           /* Insert check for returning constrained indices */
8304           indices[*loff+k] = -(off+k+1);
8305           ++cind;
8306         } else {
8307           indices[*loff+k] = off+k-cind;
8308         }
8309       }
8310     } else {
8311       for (k = 0; k < dof; ++k) {
8312         if ((cind < cdof) && (k == cdofs[cind])) {
8313           /* Insert check for returning constrained indices */
8314           indices[*loff+dof-k-1] = -(off+k+1);
8315           ++cind;
8316         } else {
8317           indices[*loff+dof-k-1] = off+k-cind;
8318         }
8319       }
8320     }
8321   }
8322   *loff += dof;
8323   PetscFunctionReturn(0);
8324 }
8325 
8326 #undef __FUNCT__
8327 #define __FUNCT__ "indicesPointFields_private"
8328 /* . off - The global offset of this point */
8329 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8330 {
8331   PetscInt       numFields, foff, f;
8332   PetscErrorCode ierr;
8333 
8334   PetscFunctionBegin;
8335   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8336   for (f = 0, foff = 0; f < numFields; ++f) {
8337     PetscInt        fdof, fcomp, cfdof;
8338     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8339     PetscInt        cind = 0, k, c;
8340 
8341     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8342     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8343     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8344     if (!cfdof || setBC) {
8345       if (orientation >= 0) {
8346         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8347       } else {
8348         for (k = fdof/fcomp-1; k >= 0; --k) {
8349           for (c = 0; c < fcomp; ++c) {
8350             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8351           }
8352         }
8353       }
8354     } else {
8355       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8356       if (orientation >= 0) {
8357         for (k = 0; k < fdof; ++k) {
8358           if ((cind < cfdof) && (k == fcdofs[cind])) {
8359             indices[foffs[f]+k] = -(off+foff+k+1);
8360             ++cind;
8361           } else {
8362             indices[foffs[f]+k] = off+foff+k-cind;
8363           }
8364         }
8365       } else {
8366         for (k = fdof/fcomp-1; k >= 0; --k) {
8367           for (c = 0; c < fcomp; ++c) {
8368             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8369               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8370               ++cind;
8371             } else {
8372               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8373             }
8374           }
8375         }
8376       }
8377     }
8378     foff     += fdof - cfdof;
8379     foffs[f] += fdof;
8380   }
8381   PetscFunctionReturn(0);
8382 }
8383 
8384 #undef __FUNCT__
8385 #define __FUNCT__ "DMPlexMatSetClosure"
8386 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8387 {
8388   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8389   PetscInt      *points = NULL;
8390   PetscInt      *indices;
8391   PetscInt       offsets[32];
8392   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8393   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8394   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8395   PetscErrorCode ierr;
8396 
8397   PetscFunctionBegin;
8398   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8399   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8400   if (useDefault) {
8401     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8402   }
8403   if (useGlobalDefault) {
8404     if (useDefault) {
8405       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8406     } else {
8407       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8408     }
8409   }
8410   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8411   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8412   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8413   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8414   /* Compress out points not in the section */
8415   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8416   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8417     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8418       points[q*2]   = points[p];
8419       points[q*2+1] = points[p+1];
8420       ++q;
8421     }
8422   }
8423   numPoints = q;
8424   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8425     PetscInt fdof;
8426 
8427     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8428     for (f = 0; f < numFields; ++f) {
8429       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8430       offsets[f+1] += fdof;
8431     }
8432     numIndices += dof;
8433   }
8434   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8435 
8436   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8437   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8438   if (numFields) {
8439     for (p = 0; p < numPoints*2; p += 2) {
8440       PetscInt o = points[p+1];
8441       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8442       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8443     }
8444   } else {
8445     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8446       PetscInt o = points[p+1];
8447       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8448       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8449     }
8450   }
8451   if (useGlobalDefault && !useDefault) {
8452     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8453   }
8454   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8455   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8456   if (ierr) {
8457     PetscMPIInt    rank;
8458     PetscErrorCode ierr2;
8459 
8460     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
8461     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8462     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8463     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8464     CHKERRQ(ierr);
8465   }
8466   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8467   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8468   PetscFunctionReturn(0);
8469 }
8470 
8471 #undef __FUNCT__
8472 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8473 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8474 {
8475   PetscSection       coordSection;
8476   Vec                coordinates;
8477   const PetscScalar *coords;
8478   const PetscInt     dim = 2;
8479   PetscInt           d, f;
8480   PetscErrorCode     ierr;
8481 
8482   PetscFunctionBegin;
8483   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8484   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8485   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8486   if (v0) {
8487     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8488   }
8489   if (J) {
8490     for (d = 0; d < dim; d++) {
8491       for (f = 0; f < dim; f++) {
8492         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8493       }
8494     }
8495     *detJ = J[0]*J[3] - J[1]*J[2];
8496 #if 0
8497     if (detJ < 0.0) {
8498       const PetscReal xLength = mesh->periodicity[0];
8499 
8500       if (xLength != 0.0) {
8501         PetscReal v0x = coords[0*dim+0];
8502 
8503         if (v0x == 0.0) v0x = v0[0] = xLength;
8504         for (f = 0; f < dim; f++) {
8505           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8506 
8507           J[0*dim+f] = 0.5*(px - v0x);
8508         }
8509       }
8510       detJ = J[0]*J[3] - J[1]*J[2];
8511     }
8512 #endif
8513     PetscLogFlops(8.0 + 3.0);
8514   }
8515   if (invJ) {
8516     const PetscReal invDet = 1.0/(*detJ);
8517 
8518     invJ[0] =  invDet*J[3];
8519     invJ[1] = -invDet*J[1];
8520     invJ[2] = -invDet*J[2];
8521     invJ[3] =  invDet*J[0];
8522     PetscLogFlops(5.0);
8523   }
8524   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8525   PetscFunctionReturn(0);
8526 }
8527 
8528 #undef __FUNCT__
8529 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8530 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8531 {
8532   PetscSection       coordSection;
8533   Vec                coordinates;
8534   const PetscScalar *coords;
8535   const PetscInt     dim = 2;
8536   PetscInt           d, f;
8537   PetscErrorCode     ierr;
8538 
8539   PetscFunctionBegin;
8540   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8541   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8542   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8543   if (v0) {
8544     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8545   }
8546   if (J) {
8547     for (d = 0; d < dim; d++) {
8548       for (f = 0; f < dim; f++) {
8549         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8550       }
8551     }
8552     *detJ = J[0]*J[3] - J[1]*J[2];
8553     PetscLogFlops(8.0 + 3.0);
8554   }
8555   if (invJ) {
8556     const PetscReal invDet = 1.0/(*detJ);
8557 
8558     invJ[0] =  invDet*J[3];
8559     invJ[1] = -invDet*J[1];
8560     invJ[2] = -invDet*J[2];
8561     invJ[3] =  invDet*J[0];
8562     PetscLogFlops(5.0);
8563   }
8564   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8565   PetscFunctionReturn(0);
8566 }
8567 
8568 #undef __FUNCT__
8569 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8570 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8571 {
8572   PetscSection       coordSection;
8573   Vec                coordinates;
8574   const PetscScalar *coords;
8575   const PetscInt     dim = 3;
8576   PetscInt           d, f;
8577   PetscErrorCode     ierr;
8578 
8579   PetscFunctionBegin;
8580   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8581   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8582   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8583   if (v0) {
8584     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8585   }
8586   if (J) {
8587     for (d = 0; d < dim; d++) {
8588       for (f = 0; f < dim; f++) {
8589         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8590       }
8591     }
8592     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8593     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8594              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8595              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8596     PetscLogFlops(18.0 + 12.0);
8597   }
8598   if (invJ) {
8599     const PetscReal invDet = 1.0/(*detJ);
8600 
8601     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8602     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8603     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8604     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8605     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8606     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8607     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8608     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8609     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8610     PetscLogFlops(37.0);
8611   }
8612   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8613   PetscFunctionReturn(0);
8614 }
8615 
8616 #undef __FUNCT__
8617 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8618 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8619 {
8620   PetscSection       coordSection;
8621   Vec                coordinates;
8622   const PetscScalar *coords;
8623   const PetscInt     dim = 3;
8624   PetscInt           d;
8625   PetscErrorCode     ierr;
8626 
8627   PetscFunctionBegin;
8628   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8629   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8630   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8631   if (v0) {
8632     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8633   }
8634   if (J) {
8635     for (d = 0; d < dim; d++) {
8636       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8637       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8638       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8639     }
8640     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8641              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8642              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8643     PetscLogFlops(18.0 + 12.0);
8644   }
8645   if (invJ) {
8646     const PetscReal invDet = -1.0/(*detJ);
8647 
8648     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8649     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8650     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8651     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8652     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8653     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8654     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8655     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8656     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8657     PetscLogFlops(37.0);
8658   }
8659   *detJ *= 8.0;
8660   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8661   PetscFunctionReturn(0);
8662 }
8663 
8664 #undef __FUNCT__
8665 #define __FUNCT__ "DMPlexComputeCellGeometry"
8666 /*@C
8667   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8668 
8669   Collective on DM
8670 
8671   Input Arguments:
8672 + dm   - the DM
8673 - cell - the cell
8674 
8675   Output Arguments:
8676 + v0   - the translation part of this affine transform
8677 . J    - the Jacobian of the transform to the reference element
8678 . invJ - the inverse of the Jacobian
8679 - detJ - the Jacobian determinant
8680 
8681   Level: advanced
8682 
8683 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8684 @*/
8685 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
8686 {
8687   PetscInt       dim, coneSize;
8688   PetscErrorCode ierr;
8689 
8690   PetscFunctionBegin;
8691   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8692   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8693   switch (dim) {
8694   case 2:
8695     switch (coneSize) {
8696     case 3:
8697       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8698       break;
8699     case 4:
8700       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8701       break;
8702     default:
8703       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8704     }
8705     break;
8706   case 3:
8707     switch (coneSize) {
8708     case 4:
8709       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8710       break;
8711     case 8:
8712       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8713       break;
8714     default:
8715       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8716     }
8717     break;
8718   default:
8719     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8720   }
8721   PetscFunctionReturn(0);
8722 }
8723 
8724 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8725 {
8726   switch (i) {
8727   case 0:
8728     switch (j) {
8729     case 0: return 0;
8730     case 1:
8731       switch (k) {
8732       case 0: return 0;
8733       case 1: return 0;
8734       case 2: return 1;
8735       }
8736     case 2:
8737       switch (k) {
8738       case 0: return 0;
8739       case 1: return -1;
8740       case 2: return 0;
8741       }
8742     }
8743   case 1:
8744     switch (j) {
8745     case 0:
8746       switch (k) {
8747       case 0: return 0;
8748       case 1: return 0;
8749       case 2: return -1;
8750       }
8751     case 1: return 0;
8752     case 2:
8753       switch (k) {
8754       case 0: return 1;
8755       case 1: return 0;
8756       case 2: return 0;
8757       }
8758     }
8759   case 2:
8760     switch (j) {
8761     case 0:
8762       switch (k) {
8763       case 0: return 0;
8764       case 1: return 1;
8765       case 2: return 0;
8766       }
8767     case 1:
8768       switch (k) {
8769       case 0: return -1;
8770       case 1: return 0;
8771       case 2: return 0;
8772       }
8773     case 2: return 0;
8774     }
8775   }
8776   return 0;
8777 }
8778 
8779 #undef __FUNCT__
8780 #define __FUNCT__ "DMPlexCreateRigidBody"
8781 /*@C
8782   DMPlexCreateRigidBody - create rigid body modes from coordinates
8783 
8784   Collective on DM
8785 
8786   Input Arguments:
8787 + dm - the DM
8788 . section - the local section associated with the rigid field, or NULL for the default section
8789 - globalSection - the global section associated with the rigid field, or NULL for the default section
8790 
8791   Output Argument:
8792 . sp - the null space
8793 
8794   Note: This is necessary to take account of Dirichlet conditions on the displacements
8795 
8796   Level: advanced
8797 
8798 .seealso: MatNullSpaceCreate()
8799 @*/
8800 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8801 {
8802   MPI_Comm       comm;
8803   Vec            coordinates, localMode, mode[6];
8804   PetscSection   coordSection;
8805   PetscScalar   *coords;
8806   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8807   PetscErrorCode ierr;
8808 
8809   PetscFunctionBegin;
8810   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
8811   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8812   if (dim == 1) {
8813     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
8814     PetscFunctionReturn(0);
8815   }
8816   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8817   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8818   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8819   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8820   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8821   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8822   m    = (dim*(dim+1))/2;
8823   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8824   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8825   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8826   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8827   /* Assume P1 */
8828   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8829   for (d = 0; d < dim; ++d) {
8830     PetscScalar values[3] = {0.0, 0.0, 0.0};
8831 
8832     values[d] = 1.0;
8833     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
8834     for (v = vStart; v < vEnd; ++v) {
8835       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8836     }
8837     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8838     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8839   }
8840   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8841   for (d = dim; d < dim*(dim+1)/2; ++d) {
8842     PetscInt i, j, k = dim > 2 ? d - dim : d;
8843 
8844     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8845     for (v = vStart; v < vEnd; ++v) {
8846       PetscScalar values[3] = {0.0, 0.0, 0.0};
8847       PetscInt    off;
8848 
8849       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8850       for (i = 0; i < dim; ++i) {
8851         for (j = 0; j < dim; ++j) {
8852           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
8853         }
8854       }
8855       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8856     }
8857     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8858     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8859   }
8860   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8861   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
8862   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
8863   /* Orthonormalize system */
8864   for (i = dim; i < m; ++i) {
8865     PetscScalar dots[6];
8866 
8867     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
8868     for (j = 0; j < i; ++j) dots[j] *= -1.0;
8869     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
8870     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
8871   }
8872   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
8873   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
8874   PetscFunctionReturn(0);
8875 }
8876 
8877 #undef __FUNCT__
8878 #define __FUNCT__ "DMPlexGetHybridBounds"
8879 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
8880 {
8881   DM_Plex       *mesh = (DM_Plex*) dm->data;
8882   PetscInt       dim;
8883   PetscErrorCode ierr;
8884 
8885   PetscFunctionBegin;
8886   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8887   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8888   if (cMax) *cMax = mesh->hybridPointMax[dim];
8889   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
8890   if (eMax) *eMax = mesh->hybridPointMax[1];
8891   if (vMax) *vMax = mesh->hybridPointMax[0];
8892   PetscFunctionReturn(0);
8893 }
8894 
8895 #undef __FUNCT__
8896 #define __FUNCT__ "DMPlexSetHybridBounds"
8897 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
8898 {
8899   DM_Plex       *mesh = (DM_Plex*) dm->data;
8900   PetscInt       dim;
8901   PetscErrorCode ierr;
8902 
8903   PetscFunctionBegin;
8904   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8905   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8906   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
8907   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
8908   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
8909   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
8910   PetscFunctionReturn(0);
8911 }
8912 
8913 #undef __FUNCT__
8914 #define __FUNCT__ "DMPlexGetVTKCellHeight"
8915 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8916 {
8917   DM_Plex *mesh = (DM_Plex*) dm->data;
8918 
8919   PetscFunctionBegin;
8920   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8921   PetscValidPointer(cellHeight, 2);
8922   *cellHeight = mesh->vtkCellHeight;
8923   PetscFunctionReturn(0);
8924 }
8925 
8926 #undef __FUNCT__
8927 #define __FUNCT__ "DMPlexSetVTKCellHeight"
8928 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8929 {
8930   DM_Plex *mesh = (DM_Plex*) dm->data;
8931 
8932   PetscFunctionBegin;
8933   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8934   mesh->vtkCellHeight = cellHeight;
8935   PetscFunctionReturn(0);
8936 }
8937 
8938 #undef __FUNCT__
8939 #define __FUNCT__ "DMPlexCreateNumbering_Private"
8940 /* We can easily have a form that takes an IS instead */
8941 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
8942 {
8943   PetscSection   section, globalSection;
8944   PetscInt      *numbers, p;
8945   PetscErrorCode ierr;
8946 
8947   PetscFunctionBegin;
8948   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
8949   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
8950   for (p = pStart; p < pEnd; ++p) {
8951     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
8952   }
8953   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
8954   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8955   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
8956   for (p = pStart; p < pEnd; ++p) {
8957     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
8958   }
8959   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
8960   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
8961   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8962   PetscFunctionReturn(0);
8963 }
8964 
8965 #undef __FUNCT__
8966 #define __FUNCT__ "DMPlexGetCellNumbering"
8967 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8968 {
8969   DM_Plex       *mesh = (DM_Plex*) dm->data;
8970   PetscInt       cellHeight, cStart, cEnd, cMax;
8971   PetscErrorCode ierr;
8972 
8973   PetscFunctionBegin;
8974   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8975   if (!mesh->globalCellNumbers) {
8976     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8977     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8978     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
8979     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8980     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
8981   }
8982   *globalCellNumbers = mesh->globalCellNumbers;
8983   PetscFunctionReturn(0);
8984 }
8985 
8986 #undef __FUNCT__
8987 #define __FUNCT__ "DMPlexGetVertexNumbering"
8988 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8989 {
8990   DM_Plex       *mesh = (DM_Plex*) dm->data;
8991   PetscInt       vStart, vEnd, vMax;
8992   PetscErrorCode ierr;
8993 
8994   PetscFunctionBegin;
8995   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8996   if (!mesh->globalVertexNumbers) {
8997     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8998     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
8999     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9000     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9001   }
9002   *globalVertexNumbers = mesh->globalVertexNumbers;
9003   PetscFunctionReturn(0);
9004 }
9005 
9006 #undef __FUNCT__
9007 #define __FUNCT__ "DMPlexGetScale"
9008 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9009 {
9010   DM_Plex *mesh = (DM_Plex*) dm->data;
9011 
9012   PetscFunctionBegin;
9013   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9014   PetscValidPointer(scale, 3);
9015   *scale = mesh->scale[unit];
9016   PetscFunctionReturn(0);
9017 }
9018 
9019 #undef __FUNCT__
9020 #define __FUNCT__ "DMPlexSetScale"
9021 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9022 {
9023   DM_Plex *mesh = (DM_Plex*) dm->data;
9024 
9025   PetscFunctionBegin;
9026   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9027   mesh->scale[unit] = scale;
9028   PetscFunctionReturn(0);
9029 }
9030 
9031 
9032 /*******************************************************************************
9033 This should be in a separate Discretization object, but I am not sure how to lay
9034 it out yet, so I am stuffing things here while I experiment.
9035 *******************************************************************************/
9036 #undef __FUNCT__
9037 #define __FUNCT__ "DMPlexSetFEMIntegration"
9038 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9039                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9040                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9041                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9042                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9043                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], 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                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9050                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9051                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9052                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9053                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9054                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9055 {
9056   DM_Plex *mesh = (DM_Plex*) dm->data;
9057 
9058   PetscFunctionBegin;
9059   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9060   mesh->integrateResidualFEM       = integrateResidualFEM;
9061   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9062   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9063   PetscFunctionReturn(0);
9064 }
9065 
9066 #undef __FUNCT__
9067 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9068 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9069 {
9070   Vec            coordinates;
9071   PetscSection   section, cSection;
9072   PetscInt       dim, vStart, vEnd, v, c, d;
9073   PetscScalar   *values, *cArray;
9074   PetscReal     *coords;
9075   PetscErrorCode ierr;
9076 
9077   PetscFunctionBegin;
9078   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9079   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9080   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9081   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9082   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9083   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9084   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9085   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9086   for (v = vStart; v < vEnd; ++v) {
9087     PetscInt dof, off;
9088 
9089     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9090     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9091     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9092     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9093     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9094     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9095   }
9096   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9097   /* Temporary, must be replaced by a projection on the finite element basis */
9098   {
9099     PetscInt eStart = 0, eEnd = 0, e, depth;
9100 
9101     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9102     --depth;
9103     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9104     for (e = eStart; e < eEnd; ++e) {
9105       const PetscInt *cone = NULL;
9106       PetscInt        coneSize, d;
9107       PetscScalar    *coordsA, *coordsB;
9108 
9109       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9110       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9111       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9112       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9113       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9114       for (d = 0; d < dim; ++d) {
9115         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9116       }
9117       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9118       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9119     }
9120   }
9121 
9122   ierr = PetscFree(coords);CHKERRQ(ierr);
9123   ierr = PetscFree(values);CHKERRQ(ierr);
9124 #if 0
9125   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9126   PetscReal      detJ;
9127 
9128   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9129   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9130   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9131 
9132   for (PetscInt c = cStart; c < cEnd; ++c) {
9133     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9134     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9135     const int                          oSize   = pV.getSize();
9136     int                                v       = 0;
9137 
9138     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9139     for (PetscInt cl = 0; cl < oSize; ++cl) {
9140       const PetscInt fDim;
9141 
9142       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9143       if (pointDim) {
9144         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9145           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9146         }
9147       }
9148     }
9149     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9150     pV.clear();
9151   }
9152   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9153   ierr = PetscFree(values);CHKERRQ(ierr);
9154 #endif
9155   PetscFunctionReturn(0);
9156 }
9157 
9158 #undef __FUNCT__
9159 #define __FUNCT__ "DMPlexProjectFunction"
9160 /*@C
9161   DMPlexProjectFunction - This projects the given function into the function space provided.
9162 
9163   Input Parameters:
9164 + dm      - The DM
9165 . numComp - The number of components (functions)
9166 . funcs   - The coordinate functions to evaluate
9167 - mode    - The insertion mode for values
9168 
9169   Output Parameter:
9170 . X - vector
9171 
9172   Level: developer
9173 
9174   Note:
9175   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9176   We will eventually fix it.
9177 
9178 ,seealso: DMPlexComputeL2Diff()
9179 */
9180 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9181 {
9182   Vec            localX;
9183   PetscErrorCode ierr;
9184 
9185   PetscFunctionBegin;
9186   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9187   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9188   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9189   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9190   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9191   PetscFunctionReturn(0);
9192 }
9193 
9194 #undef __FUNCT__
9195 #define __FUNCT__ "DMPlexComputeL2Diff"
9196 /*@C
9197   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9198 
9199   Input Parameters:
9200 + dm    - The DM
9201 . quad  - The PetscQuadrature object for each field
9202 . funcs - The functions to evaluate for each field component
9203 - X     - The coefficient vector u_h
9204 
9205   Output Parameter:
9206 . diff - The diff ||u - u_h||_2
9207 
9208   Level: developer
9209 
9210 .seealso: DMPlexProjectFunction()
9211 */
9212 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9213 {
9214   const PetscInt debug = 0;
9215   PetscSection   section;
9216   Vec            localX;
9217   PetscReal     *coords, *v0, *J, *invJ, detJ;
9218   PetscReal      localDiff = 0.0;
9219   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9220   PetscErrorCode ierr;
9221 
9222   PetscFunctionBegin;
9223   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9224   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9225   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9226   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9227   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9228   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9229   for (field = 0; field < numFields; ++field) {
9230     numComponents += quad[field].numComponents;
9231   }
9232   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9233   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9234   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9235   for (c = cStart; c < cEnd; ++c) {
9236     const PetscScalar *x;
9237     PetscReal          elemDiff = 0.0;
9238 
9239     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9240     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9241     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9242 
9243     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9244       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9245       const PetscReal *quadPoints    = quad[field].quadPoints;
9246       const PetscReal *quadWeights   = quad[field].quadWeights;
9247       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9248       const PetscInt   numBasisComps = quad[field].numComponents;
9249       const PetscReal *basis         = quad[field].basis;
9250       PetscInt         q, d, e, fc, f;
9251 
9252       if (debug) {
9253         char title[1024];
9254         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9255         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9256       }
9257       for (q = 0; q < numQuadPoints; ++q) {
9258         for (d = 0; d < dim; d++) {
9259           coords[d] = v0[d];
9260           for (e = 0; e < dim; e++) {
9261             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9262           }
9263         }
9264         for (fc = 0; fc < numBasisComps; ++fc) {
9265           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9266           PetscReal       interpolant = 0.0;
9267           for (f = 0; f < numBasisFuncs; ++f) {
9268             const PetscInt fidx = f*numBasisComps+fc;
9269             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9270           }
9271           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9272           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9273         }
9274       }
9275       comp        += numBasisComps;
9276       fieldOffset += numBasisFuncs*numBasisComps;
9277     }
9278     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9279     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9280     localDiff += elemDiff;
9281   }
9282   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9283   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9284   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9285   *diff = PetscSqrtReal(*diff);
9286   PetscFunctionReturn(0);
9287 }
9288 
9289 #undef __FUNCT__
9290 #define __FUNCT__ "DMPlexComputeResidualFEM"
9291 /*@
9292   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9293 
9294   Input Parameters:
9295 + dm - The mesh
9296 . X  - Local input vector
9297 - user - The user context
9298 
9299   Output Parameter:
9300 . F  - Local output vector
9301 
9302   Note:
9303   The second member of the user context must be an FEMContext.
9304 
9305   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9306   like a GPU, or vectorize on a multicore machine.
9307 
9308 .seealso: DMPlexComputeJacobianActionFEM()
9309 */
9310 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9311 {
9312   DM_Plex         *mesh = (DM_Plex*) dm->data;
9313   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9314   PetscQuadrature *quad = fem->quad;
9315   PetscSection     section;
9316   PetscReal       *v0, *J, *invJ, *detJ;
9317   PetscScalar     *elemVec, *u;
9318   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9319   PetscInt         cellDof = 0, numComponents = 0;
9320   PetscErrorCode   ierr;
9321 
9322   PetscFunctionBegin;
9323   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9324   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9325   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9326   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9327   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9328   numCells = cEnd - cStart;
9329   for (field = 0; field < numFields; ++field) {
9330     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9331     numComponents += quad[field].numComponents;
9332   }
9333   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9334   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9335   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);
9336   for (c = cStart; c < cEnd; ++c) {
9337     const PetscScalar *x;
9338     PetscInt           i;
9339 
9340     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9341     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9342     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9343 
9344     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9345     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9346   }
9347   for (field = 0; field < numFields; ++field) {
9348     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9349     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9350     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9351     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9352     /* Conforming batches */
9353     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9354     PetscInt numBlocks  = 1;
9355     PetscInt batchSize  = numBlocks * blockSize;
9356     PetscInt numBatches = numBatchesTmp;
9357     PetscInt numChunks  = numCells / (numBatches*batchSize);
9358     /* Remainder */
9359     PetscInt numRemainder = numCells % (numBatches * batchSize);
9360     PetscInt offset       = numCells - numRemainder;
9361 
9362     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9363     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9364                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9365   }
9366   for (c = cStart; c < cEnd; ++c) {
9367     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9368     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9369   }
9370   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9371   if (mesh->printFEM) {
9372     PetscMPIInt rank, numProcs;
9373     PetscInt    p;
9374 
9375     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9376     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9377     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9378     for (p = 0; p < numProcs; ++p) {
9379       if (p == rank) {
9380         Vec f;
9381 
9382         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9383         ierr = VecCopy(F, f);CHKERRQ(ierr);
9384         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9385         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9386         ierr = VecDestroy(&f);CHKERRQ(ierr);
9387         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9388       }
9389       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9390     }
9391   }
9392   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9393   PetscFunctionReturn(0);
9394 }
9395 
9396 #undef __FUNCT__
9397 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9398 /*@C
9399   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9400 
9401   Input Parameters:
9402 + dm - The mesh
9403 . J  - The Jacobian shell matrix
9404 . X  - Local input vector
9405 - user - The user context
9406 
9407   Output Parameter:
9408 . F  - Local output vector
9409 
9410   Note:
9411   The second member of the user context must be an FEMContext.
9412 
9413   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9414   like a GPU, or vectorize on a multicore machine.
9415 
9416 .seealso: DMPlexComputeResidualFEM()
9417 */
9418 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9419 {
9420   DM_Plex         *mesh = (DM_Plex*) dm->data;
9421   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9422   PetscQuadrature *quad = fem->quad;
9423   PetscSection     section;
9424   JacActionCtx    *jctx;
9425   PetscReal       *v0, *J, *invJ, *detJ;
9426   PetscScalar     *elemVec, *u, *a;
9427   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9428   PetscInt         cellDof = 0;
9429   PetscErrorCode   ierr;
9430 
9431   PetscFunctionBegin;
9432   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9433   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9434   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9435   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9436   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9437   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9438   numCells = cEnd - cStart;
9439   for (field = 0; field < numFields; ++field) {
9440     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9441   }
9442   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9443   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);
9444   for (c = cStart; c < cEnd; ++c) {
9445     const PetscScalar *x;
9446     PetscInt           i;
9447 
9448     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9449     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9450     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9451     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9452     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9453     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9454     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9455     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9456   }
9457   for (field = 0; field < numFields; ++field) {
9458     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9459     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9460     /* Conforming batches */
9461     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9462     PetscInt numBlocks  = 1;
9463     PetscInt batchSize  = numBlocks * blockSize;
9464     PetscInt numBatches = numBatchesTmp;
9465     PetscInt numChunks  = numCells / (numBatches*batchSize);
9466     /* Remainder */
9467     PetscInt numRemainder = numCells % (numBatches * batchSize);
9468     PetscInt offset       = numCells - numRemainder;
9469 
9470     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);
9471     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],
9472                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9473   }
9474   for (c = cStart; c < cEnd; ++c) {
9475     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9476     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9477   }
9478   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9479   if (mesh->printFEM) {
9480     PetscMPIInt rank, numProcs;
9481     PetscInt    p;
9482 
9483     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9484     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9485     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9486     for (p = 0; p < numProcs; ++p) {
9487       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9488       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9489     }
9490   }
9491   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9492   PetscFunctionReturn(0);
9493 }
9494 
9495 #undef __FUNCT__
9496 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9497 /*@
9498   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9499 
9500   Input Parameters:
9501 + dm - The mesh
9502 . X  - Local input vector
9503 - user - The user context
9504 
9505   Output Parameter:
9506 . Jac  - Jacobian matrix
9507 
9508   Note:
9509   The second member of the user context must be an FEMContext.
9510 
9511   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9512   like a GPU, or vectorize on a multicore machine.
9513 
9514 .seealso: FormFunctionLocal()
9515 */
9516 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9517 {
9518   DM_Plex         *mesh = (DM_Plex*) dm->data;
9519   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9520   PetscQuadrature *quad = fem->quad;
9521   PetscSection     section;
9522   PetscReal       *v0, *J, *invJ, *detJ;
9523   PetscScalar     *elemMat, *u;
9524   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9525   PetscInt         cellDof = 0, numComponents = 0;
9526   PetscBool        isShell;
9527   PetscErrorCode   ierr;
9528 
9529   PetscFunctionBegin;
9530   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9531   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9532   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9533   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9534   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9535   numCells = cEnd - cStart;
9536   for (field = 0; field < numFields; ++field) {
9537     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9538     numComponents += quad[field].numComponents;
9539   }
9540   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9541   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9542   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);
9543   for (c = cStart; c < cEnd; ++c) {
9544     const PetscScalar *x;
9545     PetscInt           i;
9546 
9547     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9548     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9549     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9550 
9551     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9552     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9553   }
9554   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9555   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9556     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9557     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9558     PetscInt       fieldJ;
9559 
9560     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9561       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9562       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9563       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9564       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9565       /* Conforming batches */
9566       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9567       PetscInt numBlocks  = 1;
9568       PetscInt batchSize  = numBlocks * blockSize;
9569       PetscInt numBatches = numBatchesTmp;
9570       PetscInt numChunks  = numCells / (numBatches*batchSize);
9571       /* Remainder */
9572       PetscInt numRemainder = numCells % (numBatches * batchSize);
9573       PetscInt offset       = numCells - numRemainder;
9574 
9575       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9576       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9577                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9578     }
9579   }
9580   for (c = cStart; c < cEnd; ++c) {
9581     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9582     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9583   }
9584   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9585 
9586   /* Assemble matrix, using the 2-step process:
9587        MatAssemblyBegin(), MatAssemblyEnd(). */
9588   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9589   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9590 
9591   if (mesh->printFEM) {
9592     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9593     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9594     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9595   }
9596   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9597   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9598   if (isShell) {
9599     JacActionCtx *jctx;
9600 
9601     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9602     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9603   }
9604   *str = SAME_NONZERO_PATTERN;
9605   PetscFunctionReturn(0);
9606 }
9607 
9608 
9609 #undef __FUNCT__
9610 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9611 /*@C
9612   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9613   the local section and an SF describing the section point overlap.
9614 
9615   Input Parameters:
9616   + s - The PetscSection for the local field layout
9617   . sf - The SF describing parallel layout of the section points
9618   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9619   . label - The label specifying the points
9620   - labelValue - The label stratum specifying the points
9621 
9622   Output Parameter:
9623   . gsection - The PetscSection for the global field layout
9624 
9625   Note: This gives negative sizes and offsets to points not owned by this process
9626 
9627   Level: developer
9628 
9629 .seealso: PetscSectionCreate()
9630 @*/
9631 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9632 {
9633   PetscInt      *neg;
9634   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9635   PetscErrorCode ierr;
9636 
9637   PetscFunctionBegin;
9638   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9639   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9640   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9641   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9642   /* Mark ghost points with negative dof */
9643   for (p = pStart; p < pEnd; ++p) {
9644     PetscInt value;
9645 
9646     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9647     if (value != labelValue) continue;
9648     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9649     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9650     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9651     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9652     neg[p-pStart] = -(dof+1);
9653   }
9654   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9655   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
9656   if (nroots >= 0) {
9657     if (nroots > pEnd - pStart) {
9658       PetscInt *tmpDof;
9659       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9660       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9661       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9662       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9663       for (p = pStart; p < pEnd; ++p) {
9664         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
9665       }
9666       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9667     } else {
9668       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9669       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9670     }
9671   }
9672   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9673   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9674     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9675 
9676     (*gsection)->atlasOff[p] = off;
9677 
9678     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9679   }
9680   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9681   globalOff -= off;
9682   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9683     (*gsection)->atlasOff[p] += globalOff;
9684 
9685     neg[p] = -((*gsection)->atlasOff[p]+1);
9686   }
9687   /* Put in negative offsets for ghost points */
9688   if (nroots >= 0) {
9689     if (nroots > pEnd - pStart) {
9690       PetscInt *tmpOff;
9691       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9692       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9693       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9694       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9695       for (p = pStart; p < pEnd; ++p) {
9696         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
9697       }
9698       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9699     } else {
9700       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9701       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9702     }
9703   }
9704   ierr = PetscFree(neg);CHKERRQ(ierr);
9705   PetscFunctionReturn(0);
9706 }
9707