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