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