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