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