xref: /petsc/src/dm/impls/plex/plex.c (revision d5f5d44e0e6c2dc9cad3bce1bdac11fc9542197f)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/isimpl.h>
3 #include <petsc/private/vecimpl.h>
4 #include <petsc/private/glvisvecimpl.h>
5 #include <petscsf.h>
6 #include <petscds.h>
7 #include <petscdraw.h>
8 #include <petscdmfield.h>
9 
10 /* Logging support */
11 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;
12 
13 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
14 
15 /*@
16   DMPlexRefineSimplexToTensor - Uniformly refines simplicial cells into tensor product cells.
17   3 quadrilaterals per triangle in 2D and 4 hexahedra per tetrahedron in 3D.
18 
19   Collective
20 
21   Input Parameters:
22 . dm - The DMPlex object
23 
24   Output Parameters:
25 . dmRefined - The refined DMPlex object
26 
27   Note: Returns NULL if the mesh is already a tensor product mesh.
28 
29   Level: intermediate
30 
31 .seealso: DMPlexCreate(), DMPlexSetRefinementUniform()
32 @*/
33 PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined)
34 {
35   PetscInt         dim, cMax, fMax, cStart, cEnd, coneSize;
36   CellRefiner      cellRefiner;
37   PetscBool        lop, allnoop, localized;
38   PetscErrorCode   ierr;
39 
40   PetscFunctionBegin;
41   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
42   PetscValidPointer(dmRefined, 1);
43   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
44   ierr = DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);CHKERRQ(ierr);
45   ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
46   if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP;
47   else {
48     ierr = DMPlexGetConeSize(dm,cStart,&coneSize);CHKERRQ(ierr);
49     switch (dim) {
50     case 1:
51       cellRefiner = REFINER_NOOP;
52     break;
53     case 2:
54       switch (coneSize) {
55       case 3:
56         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
57         else cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
58       break;
59       case 4:
60         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
61         else cellRefiner = REFINER_NOOP;
62       break;
63       default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
64       }
65     break;
66     case 3:
67       switch (coneSize) {
68       case 4:
69         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
70         else cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
71       break;
72       case 5:
73         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
74         else cellRefiner = REFINER_NOOP;
75       break;
76       case 6:
77         if (cMax >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Simplex2Tensor in 3D with Hybrid mesh not yet done");
78         cellRefiner = REFINER_NOOP;
79       break;
80       default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
81       }
82     break;
83     default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle dimension %D",dim);
84     }
85   }
86   /* return if we don't need to refine */
87   lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
88   ierr = MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
89   if (allnoop) {
90     *dmRefined = NULL;
91     PetscFunctionReturn(0);
92   }
93   ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
94   ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
95   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
96   if (localized) {
97     ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);
98   }
99   PetscFunctionReturn(0);
100 }
101 
102 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
103 {
104   PetscInt       dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior;
105   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];
106   PetscErrorCode ierr;
107 
108   PetscFunctionBegin;
109   *ft  = PETSC_VTK_POINT_FIELD;
110   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
111   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
112   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
113   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
114   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
115   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
116   if (field >= 0) {
117     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);CHKERRQ(ierr);}
118     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);CHKERRQ(ierr);}
119   } else {
120     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vcdof[0]);CHKERRQ(ierr);}
121     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &vcdof[1]);CHKERRQ(ierr);}
122   }
123   ierr = MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
124   if (globalvcdof[0]) {
125     *sStart = vStart;
126     *sEnd   = vEnd;
127     if (globalvcdof[0] == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
128     else                       *ft = PETSC_VTK_POINT_FIELD;
129   } else if (globalvcdof[1]) {
130     *sStart = cStart;
131     *sEnd   = cEnd;
132     if (globalvcdof[1] == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
133     else                       *ft = PETSC_VTK_CELL_FIELD;
134   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
135   PetscFunctionReturn(0);
136 }
137 
138 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
139 {
140   DM                 dm;
141   PetscSection       s;
142   PetscDraw          draw, popup;
143   DM                 cdm;
144   PetscSection       coordSection;
145   Vec                coordinates;
146   const PetscScalar *coords, *array;
147   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
148   PetscReal          vbound[2], time;
149   PetscBool          isnull, flg;
150   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
151   const char        *name;
152   char               title[PETSC_MAX_PATH_LEN];
153   PetscErrorCode     ierr;
154 
155   PetscFunctionBegin;
156   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
157   ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr);
158   if (isnull) PetscFunctionReturn(0);
159 
160   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
161   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
162   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
163   ierr = DMGetSection(dm, &s);CHKERRQ(ierr);
164   ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr);
165   ierr = DMGetCoarsenLevel(dm, &level);CHKERRQ(ierr);
166   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
167   ierr = DMGetSection(cdm, &coordSection);CHKERRQ(ierr);
168   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
169   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
170   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
171 
172   ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
173   ierr = DMGetOutputSequenceNumber(dm, &step, &time);CHKERRQ(ierr);
174 
175   ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr);
176   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
177   for (c = 0; c < N; c += dim) {
178     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
179     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
180   }
181   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
182   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
183 
184   /* Could implement something like DMDASelectFields() */
185   for (f = 0; f < Nf; ++f) {
186     DM   fdm = dm;
187     Vec  fv  = v;
188     IS   fis;
189     char prefix[PETSC_MAX_PATH_LEN];
190     const char *fname;
191 
192     ierr = PetscSectionGetFieldComponents(s, f, &Nc);CHKERRQ(ierr);
193     ierr = PetscSectionGetFieldName(s, f, &fname);CHKERRQ(ierr);
194 
195     if (v->hdr.prefix) {ierr = PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));CHKERRQ(ierr);}
196     else               {prefix[0] = '\0';}
197     if (Nf > 1) {
198       ierr = DMCreateSubDM(dm, 1, &f, &fis, &fdm);CHKERRQ(ierr);
199       ierr = VecGetSubVector(v, fis, &fv);CHKERRQ(ierr);
200       ierr = PetscStrlcat(prefix, fname,sizeof(prefix));CHKERRQ(ierr);
201       ierr = PetscStrlcat(prefix, "_",sizeof(prefix));CHKERRQ(ierr);
202     }
203     for (comp = 0; comp < Nc; ++comp, ++w) {
204       PetscInt nmax = 2;
205 
206       ierr = PetscViewerDrawGetDraw(viewer, w, &draw);CHKERRQ(ierr);
207       if (Nc > 1) {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);CHKERRQ(ierr);}
208       else        {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);CHKERRQ(ierr);}
209       ierr = PetscDrawSetTitle(draw, title);CHKERRQ(ierr);
210 
211       /* TODO Get max and min only for this component */
212       ierr = PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);CHKERRQ(ierr);
213       if (!flg) {
214         ierr = VecMin(fv, NULL, &vbound[0]);CHKERRQ(ierr);
215         ierr = VecMax(fv, NULL, &vbound[1]);CHKERRQ(ierr);
216         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
217       }
218       ierr = PetscDrawGetPopup(draw, &popup);CHKERRQ(ierr);
219       ierr = PetscDrawScalePopup(popup, vbound[0], vbound[1]);CHKERRQ(ierr);
220       ierr = PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);CHKERRQ(ierr);
221 
222       ierr = VecGetArrayRead(fv, &array);CHKERRQ(ierr);
223       for (c = cStart; c < cEnd; ++c) {
224         PetscScalar *coords = NULL, *a = NULL;
225         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};
226 
227         ierr = DMPlexPointLocalRead(fdm, c, array, &a);CHKERRQ(ierr);
228         if (a) {
229           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
230           color[1] = color[2] = color[3] = color[0];
231         } else {
232           PetscScalar *vals = NULL;
233           PetscInt     numVals, va;
234 
235           ierr = DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr);
236           if (numVals % Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %D does not divide the number of values in the closure %D", Nc, numVals);
237           switch (numVals/Nc) {
238           case 3: /* P1 Triangle */
239           case 4: /* P1 Quadrangle */
240             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
241             break;
242           case 6: /* P2 Triangle */
243           case 8: /* P2 Quadrangle */
244             for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
245             break;
246           default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
247           }
248           ierr = DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr);
249         }
250         ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
251         switch (numCoords) {
252         case 6:
253           ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);CHKERRQ(ierr);
254           break;
255         case 8:
256           ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);CHKERRQ(ierr);
257           ierr = PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0]);CHKERRQ(ierr);
258           break;
259         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
260         }
261         ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
262       }
263       ierr = VecRestoreArrayRead(fv, &array);CHKERRQ(ierr);
264       ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
265       ierr = PetscDrawPause(draw);CHKERRQ(ierr);
266       ierr = PetscDrawSave(draw);CHKERRQ(ierr);
267     }
268     if (Nf > 1) {
269       ierr = VecRestoreSubVector(v, fis, &fv);CHKERRQ(ierr);
270       ierr = ISDestroy(&fis);CHKERRQ(ierr);
271       ierr = DMDestroy(&fdm);CHKERRQ(ierr);
272     }
273   }
274   PetscFunctionReturn(0);
275 }
276 
277 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
278 {
279   DM                      dm;
280   Vec                     locv;
281   const char              *name;
282   PetscSection            section;
283   PetscInt                pStart, pEnd;
284   PetscViewerVTKFieldType ft;
285   PetscErrorCode          ierr;
286 
287   PetscFunctionBegin;
288   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
289   ierr = DMCreateLocalVector(dm, &locv);CHKERRQ(ierr); /* VTK viewer requires exclusive ownership of the vector */
290   ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
291   ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
292   ierr = VecCopy(v, locv);CHKERRQ(ierr);
293   ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
294   ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr);
295   ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr);
296   PetscFunctionReturn(0);
297 }
298 
299 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
300 {
301   DM             dm;
302   PetscBool      isvtk, ishdf5, isdraw, isglvis;
303   PetscErrorCode ierr;
304 
305   PetscFunctionBegin;
306   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
307   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
308   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);CHKERRQ(ierr);
309   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
310   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);CHKERRQ(ierr);
311   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr);
312   if (isvtk || ishdf5 || isdraw || isglvis) {
313     PetscInt    i,numFields;
314     PetscObject fe;
315     PetscBool   fem = PETSC_FALSE;
316     Vec         locv = v;
317     const char  *name;
318     PetscInt    step;
319     PetscReal   time;
320 
321     ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
322     for (i=0; i<numFields; i++) {
323       ierr = DMGetField(dm, i, &fe);CHKERRQ(ierr);
324       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
325     }
326     if (fem) {
327       ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
328       ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
329       ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
330       ierr = VecCopy(v, locv);CHKERRQ(ierr);
331       ierr = DMGetOutputSequenceNumber(dm, NULL, &time);CHKERRQ(ierr);
332       ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);CHKERRQ(ierr);
333     }
334     if (isvtk) {
335       ierr = VecView_Plex_Local_VTK(locv, viewer);CHKERRQ(ierr);
336     } else if (ishdf5) {
337 #if defined(PETSC_HAVE_HDF5)
338       ierr = VecView_Plex_Local_HDF5_Internal(locv, viewer);CHKERRQ(ierr);
339 #else
340       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
341 #endif
342     } else if (isdraw) {
343       ierr = VecView_Plex_Local_Draw(locv, viewer);CHKERRQ(ierr);
344     } else if (isglvis) {
345       ierr = DMGetOutputSequenceNumber(dm, &step, NULL);CHKERRQ(ierr);
346       ierr = PetscViewerGLVisSetSnapId(viewer, step);CHKERRQ(ierr);
347       ierr = VecView_GLVis(locv, viewer);CHKERRQ(ierr);
348     }
349     if (fem) {ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);}
350   } else {
351     PetscBool isseq;
352 
353     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
354     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
355     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
356   }
357   PetscFunctionReturn(0);
358 }
359 
360 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
361 {
362   DM             dm;
363   PetscBool      isvtk, ishdf5, isdraw, isglvis;
364   PetscErrorCode ierr;
365 
366   PetscFunctionBegin;
367   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
368   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
369   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);CHKERRQ(ierr);
370   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
371   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);CHKERRQ(ierr);
372   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr);
373   if (isvtk || isdraw || isglvis) {
374     Vec         locv;
375     const char *name;
376 
377     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
378     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
379     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
380     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
381     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
382     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
383     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
384   } else if (ishdf5) {
385 #if defined(PETSC_HAVE_HDF5)
386     ierr = VecView_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr);
387 #else
388     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
389 #endif
390   } else {
391     PetscBool isseq;
392 
393     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
394     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
395     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
396   }
397   PetscFunctionReturn(0);
398 }
399 
400 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
401 {
402   DM                dm;
403   MPI_Comm          comm;
404   PetscViewerFormat format;
405   Vec               v;
406   PetscBool         isvtk, ishdf5;
407   PetscErrorCode    ierr;
408 
409   PetscFunctionBegin;
410   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
411   ierr = PetscObjectGetComm((PetscObject) originalv, &comm);CHKERRQ(ierr);
412   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
413   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
414   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
415   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);CHKERRQ(ierr);
416   if (format == PETSC_VIEWER_NATIVE) {
417     const char *vecname;
418     PetscInt    n, nroots;
419 
420     if (dm->sfNatural) {
421       ierr = VecGetLocalSize(originalv, &n);CHKERRQ(ierr);
422       ierr = PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
423       if (n == nroots) {
424         ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
425         ierr = DMPlexGlobalToNaturalBegin(dm, originalv, v);CHKERRQ(ierr);
426         ierr = DMPlexGlobalToNaturalEnd(dm, originalv, v);CHKERRQ(ierr);
427         ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
428         ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
429       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
430     } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
431   } else {
432     /* we are viewing a natural DMPlex vec. */
433     v = originalv;
434   }
435   if (ishdf5) {
436 #if defined(PETSC_HAVE_HDF5)
437     ierr = VecView_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr);
438 #else
439     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
440 #endif
441   } else if (isvtk) {
442     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
443   } else {
444     PetscBool isseq;
445 
446     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
447     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
448     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
449   }
450   if (format == PETSC_VIEWER_NATIVE) {ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);}
451   PetscFunctionReturn(0);
452 }
453 
454 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
455 {
456   DM             dm;
457   PetscBool      ishdf5;
458   PetscErrorCode ierr;
459 
460   PetscFunctionBegin;
461   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
462   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
463   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
464   if (ishdf5) {
465     DM          dmBC;
466     Vec         gv;
467     const char *name;
468 
469     ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr);
470     ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr);
471     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
472     ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr);
473     ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr);
474     ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
475     ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
476     ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr);
477   } else {
478     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
479   }
480   PetscFunctionReturn(0);
481 }
482 
483 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
484 {
485   DM             dm;
486   PetscBool      ishdf5;
487   PetscErrorCode ierr;
488 
489   PetscFunctionBegin;
490   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
491   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
492   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
493   if (ishdf5) {
494 #if defined(PETSC_HAVE_HDF5)
495     ierr = VecLoad_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr);
496 #else
497     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
498 #endif
499   } else {
500     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
501   }
502   PetscFunctionReturn(0);
503 }
504 
505 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
506 {
507   DM                dm;
508   PetscViewerFormat format;
509   PetscBool         ishdf5;
510   PetscErrorCode    ierr;
511 
512   PetscFunctionBegin;
513   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
514   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
515   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
516   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
517   if (format == PETSC_VIEWER_NATIVE) {
518     if (dm->sfNatural) {
519       if (ishdf5) {
520 #if defined(PETSC_HAVE_HDF5)
521         Vec         v;
522         const char *vecname;
523 
524         ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
525         ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
526         ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
527         ierr = VecLoad_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr);
528         ierr = DMPlexNaturalToGlobalBegin(dm, v, originalv);CHKERRQ(ierr);
529         ierr = DMPlexNaturalToGlobalEnd(dm, v, originalv);CHKERRQ(ierr);
530         ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);
531 #else
532         SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
533 #endif
534       } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
535     }
536   }
537   PetscFunctionReturn(0);
538 }
539 
540 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
541 {
542   PetscSection       coordSection;
543   Vec                coordinates;
544   DMLabel            depthLabel;
545   const char        *name[4];
546   const PetscScalar *a;
547   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
548   PetscErrorCode     ierr;
549 
550   PetscFunctionBegin;
551   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
552   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
553   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
554   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
555   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
556   ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr);
557   ierr = VecGetArrayRead(coordinates, &a);CHKERRQ(ierr);
558   name[0]     = "vertex";
559   name[1]     = "edge";
560   name[dim-1] = "face";
561   name[dim]   = "cell";
562   for (c = cStart; c < cEnd; ++c) {
563     PetscInt *closure = NULL;
564     PetscInt  closureSize, cl;
565 
566     ierr = PetscViewerASCIIPrintf(viewer, "Geometry for cell %D:\n", c);CHKERRQ(ierr);
567     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
568     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
569     for (cl = 0; cl < closureSize*2; cl += 2) {
570       PetscInt point = closure[cl], depth, dof, off, d, p;
571 
572       if ((point < pStart) || (point >= pEnd)) continue;
573       ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
574       if (!dof) continue;
575       ierr = DMLabelGetValue(depthLabel, point, &depth);CHKERRQ(ierr);
576       ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
577       ierr = PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);CHKERRQ(ierr);
578       for (p = 0; p < dof/dim; ++p) {
579         ierr = PetscViewerASCIIPrintf(viewer, " (");CHKERRQ(ierr);
580         for (d = 0; d < dim; ++d) {
581           if (d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
582           ierr = PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));CHKERRQ(ierr);
583         }
584         ierr = PetscViewerASCIIPrintf(viewer, ")");CHKERRQ(ierr);
585       }
586       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
587     }
588     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
589     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
590   }
591   ierr = VecRestoreArrayRead(coordinates, &a);CHKERRQ(ierr);
592   PetscFunctionReturn(0);
593 }
594 
595 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
596 {
597   DM_Plex          *mesh = (DM_Plex*) dm->data;
598   DM                cdm;
599   DMLabel           markers;
600   PetscSection      coordSection;
601   Vec               coordinates;
602   PetscViewerFormat format;
603   PetscErrorCode    ierr;
604 
605   PetscFunctionBegin;
606   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
607   ierr = DMGetSection(cdm, &coordSection);CHKERRQ(ierr);
608   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
609   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
610   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
611     const char *name;
612     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
613     PetscInt    pStart, pEnd, p;
614     PetscMPIInt rank, size;
615 
616     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
617     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
618     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
619     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
620     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
621     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
622     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
623     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
624     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
625     if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);CHKERRQ(ierr);}
626     ierr = PetscViewerASCIIPrintf(viewer, "Supports:\n", name);CHKERRQ(ierr);
627     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
628     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);CHKERRQ(ierr);
629     for (p = pStart; p < pEnd; ++p) {
630       PetscInt dof, off, s;
631 
632       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
633       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
634       for (s = off; s < off+dof; ++s) {
635         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
636       }
637     }
638     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
639     ierr = PetscViewerASCIIPrintf(viewer, "Cones:\n", name);CHKERRQ(ierr);
640     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);CHKERRQ(ierr);
641     for (p = pStart; p < pEnd; ++p) {
642       PetscInt dof, off, c;
643 
644       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
645       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
646       for (c = off; c < off+dof; ++c) {
647         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
648       }
649     }
650     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
651     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
652     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
653     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
654     ierr = DMGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
655     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
656     if (size > 1) {
657       PetscSF sf;
658 
659       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
660       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
661     }
662     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
663   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
664     const char  *name, *color;
665     const char  *defcolors[3]  = {"gray", "orange", "green"};
666     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
667     PetscReal    scale         = 2.0;
668     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
669     double       tcoords[3];
670     PetscScalar *coords;
671     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
672     PetscMPIInt  rank, size;
673     char         **names, **colors, **lcolors;
674     PetscBool    plotEdges, flg;
675 
676     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
677     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
678     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
679     numLabels  = PetscMax(numLabels, 10);
680     numColors  = 10;
681     numLColors = 10;
682     ierr = PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);CHKERRQ(ierr);
683     ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);CHKERRQ(ierr);
684     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);CHKERRQ(ierr);
685     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);CHKERRQ(ierr);
686     if (!useLabels) numLabels = 0;
687     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);CHKERRQ(ierr);
688     if (!useColors) {
689       numColors = 3;
690       for (c = 0; c < numColors; ++c) {ierr = PetscStrallocpy(defcolors[c], &colors[c]);CHKERRQ(ierr);}
691     }
692     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);CHKERRQ(ierr);
693     if (!useColors) {
694       numLColors = 4;
695       for (c = 0; c < numLColors; ++c) {ierr = PetscStrallocpy(deflcolors[c], &lcolors[c]);CHKERRQ(ierr);}
696     }
697     plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3);
698     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);CHKERRQ(ierr);
699     if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
700     if (depth < dim) plotEdges = PETSC_FALSE;
701     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
702     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
703     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
704     ierr = PetscViewerASCIIPrintf(viewer, "\
705 \\documentclass[tikz]{standalone}\n\n\
706 \\usepackage{pgflibraryshapes}\n\
707 \\usetikzlibrary{backgrounds}\n\
708 \\usetikzlibrary{arrows}\n\
709 \\begin{document}\n");CHKERRQ(ierr);
710     if (size > 1) {
711       ierr = PetscViewerASCIIPrintf(viewer, "%s for process ", name);CHKERRQ(ierr);
712       for (p = 0; p < size; ++p) {
713         if (p > 0 && p == size-1) {
714           ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
715         } else if (p > 0) {
716           ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
717         }
718         ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
719       }
720       ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n");CHKERRQ(ierr);
721     }
722     ierr = PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);CHKERRQ(ierr);
723     /* Plot vertices */
724     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
725     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
726     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
727     for (v = vStart; v < vEnd; ++v) {
728       PetscInt  off, dof, d;
729       PetscBool isLabeled = PETSC_FALSE;
730 
731       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
732       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
733       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
734       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
735       for (d = 0; d < dof; ++d) {
736         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
737         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
738       }
739       /* Rotate coordinates since PGF makes z point out of the page instead of up */
740       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
741       for (d = 0; d < dof; ++d) {
742         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
743         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);CHKERRQ(ierr);
744       }
745       color = colors[rank%numColors];
746       for (l = 0; l < numLabels; ++l) {
747         PetscInt val;
748         ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
749         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
750       }
751       if (useNumbers) {
752         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);CHKERRQ(ierr);
753       } else {
754         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
755       }
756     }
757     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
758     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
759     /* Plot cells */
760     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
761     if (dim == 3 || !useNumbers) {
762       for (e = eStart; e < eEnd; ++e) {
763         const PetscInt *cone;
764 
765         color = colors[rank%numColors];
766         for (l = 0; l < numLabels; ++l) {
767           PetscInt val;
768           ierr = DMGetLabelValue(dm, names[l], e, &val);CHKERRQ(ierr);
769           if (val >= 0) {color = lcolors[l%numLColors]; break;}
770         }
771         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
772         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);CHKERRQ(ierr);
773       }
774     } else {
775       for (c = cStart; c < cEnd; ++c) {
776         PetscInt *closure = NULL;
777         PetscInt  closureSize, firstPoint = -1;
778 
779         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
780         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
781         for (p = 0; p < closureSize*2; p += 2) {
782           const PetscInt point = closure[p];
783 
784           if ((point < vStart) || (point >= vEnd)) continue;
785           if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
786           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);CHKERRQ(ierr);
787           if (firstPoint < 0) firstPoint = point;
788         }
789         /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
790         ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);CHKERRQ(ierr);
791         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
792       }
793     }
794     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
795     for (c = cStart; c < cEnd; ++c) {
796       double    ccoords[3] = {0.0, 0.0, 0.0};
797       PetscBool isLabeled  = PETSC_FALSE;
798       PetscInt *closure    = NULL;
799       PetscInt  closureSize, dof, d, n = 0;
800 
801       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
802       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
803       for (p = 0; p < closureSize*2; p += 2) {
804         const PetscInt point = closure[p];
805         PetscInt       off;
806 
807         if ((point < vStart) || (point >= vEnd)) continue;
808         ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
809         ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
810         for (d = 0; d < dof; ++d) {
811           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
812           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
813         }
814         /* Rotate coordinates since PGF makes z point out of the page instead of up */
815         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
816         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
817         ++n;
818       }
819       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
820       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
821       for (d = 0; d < dof; ++d) {
822         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
823         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d]);CHKERRQ(ierr);
824       }
825       color = colors[rank%numColors];
826       for (l = 0; l < numLabels; ++l) {
827         PetscInt val;
828         ierr = DMGetLabelValue(dm, names[l], c, &val);CHKERRQ(ierr);
829         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
830       }
831       if (useNumbers) {
832         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);CHKERRQ(ierr);
833       } else {
834         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
835       }
836     }
837     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
838     /* Plot edges */
839     if (depth > 1 || plotEdges) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
840     if (plotEdges) {
841       ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
842       ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
843       for (e = eStart; e < eEnd; ++e) {
844         const PetscInt *cone;
845         PetscInt        coneSize, offA, offB, dof, d;
846 
847         ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
848         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
849         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
850         ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
851         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
852         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
853         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
854         for (d = 0; d < dof; ++d) {
855           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
856           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
857         }
858         /* Rotate coordinates since PGF makes z point out of the page instead of up */
859         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
860         for (d = 0; d < dof; ++d) {
861           if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
862           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);CHKERRQ(ierr);
863         }
864         color = colors[rank%numColors];
865         for (l = 0; l < numLabels; ++l) {
866           PetscInt val;
867           ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
868           if (val >= 0) {color = lcolors[l%numLColors]; break;}
869         }
870         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);CHKERRQ(ierr);
871       }
872       ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
873       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
874       ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
875     }
876     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
877     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
878     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");CHKERRQ(ierr);
879     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
880     for (l = 0; l < numLabels;  ++l) {ierr = PetscFree(names[l]);CHKERRQ(ierr);}
881     for (c = 0; c < numColors;  ++c) {ierr = PetscFree(colors[c]);CHKERRQ(ierr);}
882     for (c = 0; c < numLColors; ++c) {ierr = PetscFree(lcolors[c]);CHKERRQ(ierr);}
883     ierr = PetscFree3(names, colors, lcolors);CHKERRQ(ierr);
884   } else {
885     MPI_Comm    comm;
886     PetscInt   *sizes, *hybsizes;
887     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
888     PetscInt    pStart, pEnd, p;
889     PetscInt    numLabels, l;
890     const char *name;
891     PetscMPIInt size;
892 
893     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
894     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
895     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
896     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
897     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
898     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
899     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
900     if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);CHKERRQ(ierr);}
901     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
902     ierr = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
903     ierr = DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);CHKERRQ(ierr);
904     ierr = PetscCalloc2(size,&sizes,size,&hybsizes);CHKERRQ(ierr);
905     if (depth == 1) {
906       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
907       pEnd = pEnd - pStart;
908       pMax[0] -= pStart;
909       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
910       ierr = MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
911       ierr = PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);CHKERRQ(ierr);
912       for (p = 0; p < size; ++p) {
913         if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);}
914         else                  {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
915       }
916       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
917       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
918       pEnd = pEnd - pStart;
919       pMax[depth] -= pStart;
920       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
921       ierr = MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
922       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
923       for (p = 0; p < size; ++p) {
924         if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);}
925         else                  {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
926       }
927       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
928     } else {
929       PetscMPIInt rank;
930       ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
931       for (d = 0; d <= dim; d++) {
932         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
933         pEnd    -= pStart;
934         pMax[d] -= pStart;
935         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
936         ierr = MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
937         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
938         for (p = 0; p < size; ++p) {
939           if (!rank) {
940             if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);}
941             else                  {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
942           }
943         }
944         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
945       }
946     }
947     ierr = PetscFree2(sizes,hybsizes);CHKERRQ(ierr);
948     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
949     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
950     for (l = 0; l < numLabels; ++l) {
951       DMLabel         label;
952       const char     *name;
953       IS              valueIS;
954       const PetscInt *values;
955       PetscInt        numValues, v;
956 
957       ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
958       ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
959       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
960       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);CHKERRQ(ierr);
961       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
962       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
963       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
964       for (v = 0; v < numValues; ++v) {
965         PetscInt size;
966 
967         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
968         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
969         ierr = PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);CHKERRQ(ierr);
970       }
971       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
972       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
973       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
974       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
975     }
976     ierr = DMGetCoarseDM(dm, &cdm);CHKERRQ(ierr);
977     if (cdm) {
978       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
979       ierr = DMPlexView_Ascii(cdm, viewer);CHKERRQ(ierr);
980       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
981     }
982   }
983   PetscFunctionReturn(0);
984 }
985 
986 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
987 {
988   PetscDraw          draw;
989   DM                 cdm;
990   PetscSection       coordSection;
991   Vec                coordinates;
992   const PetscScalar *coords;
993   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
994   PetscBool          isnull;
995   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
996   PetscMPIInt        rank;
997   PetscErrorCode     ierr;
998 
999   PetscFunctionBegin;
1000   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
1001   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1002   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
1003   ierr = DMGetSection(cdm, &coordSection);CHKERRQ(ierr);
1004   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
1005   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1006   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1007 
1008   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
1009   ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr);
1010   if (isnull) PetscFunctionReturn(0);
1011   ierr = PetscDrawSetTitle(draw, "Mesh");CHKERRQ(ierr);
1012 
1013   ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr);
1014   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
1015   for (c = 0; c < N; c += dim) {
1016     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1017     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1018   }
1019   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
1020   ierr = MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1021   ierr = MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1022   ierr = PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);CHKERRQ(ierr);
1023   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
1024 
1025   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
1026   for (c = cStart; c < cEnd; ++c) {
1027     PetscScalar *coords = NULL;
1028     PetscInt     numCoords,coneSize;
1029 
1030     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
1031     ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
1032     switch (coneSize) {
1033     case 3:
1034       ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1035                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1036                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1037                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1038       break;
1039     case 4:
1040       ierr = PetscDrawRectangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1041                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1042                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1043                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1044                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1045       break;
1046     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1047     }
1048     ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
1049   }
1050   for (c = cStart; c < cEnd; ++c) {
1051     PetscScalar *coords = NULL;
1052     PetscInt     numCoords,coneSize;
1053 
1054     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
1055     ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
1056     switch (coneSize) {
1057     case 3:
1058       ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1059       ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1060       ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1061       break;
1062     case 4:
1063       ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1064       ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1065       ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1066       ierr = PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1067       break;
1068     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1069     }
1070     ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
1071   }
1072   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
1073   ierr = PetscDrawPause(draw);CHKERRQ(ierr);
1074   ierr = PetscDrawSave(draw);CHKERRQ(ierr);
1075   PetscFunctionReturn(0);
1076 }
1077 
1078 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1079 {
1080   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1081   PetscErrorCode    ierr;
1082 
1083   PetscFunctionBegin;
1084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1085   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1086   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1087   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);CHKERRQ(ierr);
1088   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
1089   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);CHKERRQ(ierr);
1090   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr);
1091   if (iascii) {
1092     PetscViewerFormat format;
1093     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1094     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1095       ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr);
1096     } else {
1097       ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
1098     }
1099   } else if (ishdf5) {
1100 #if defined(PETSC_HAVE_HDF5)
1101     ierr = DMPlexView_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1102 #else
1103     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1104 #endif
1105   } else if (isvtk) {
1106     ierr = DMPlexVTKWriteAll((PetscObject) dm,viewer);CHKERRQ(ierr);
1107   } else if (isdraw) {
1108     ierr = DMPlexView_Draw(dm, viewer);CHKERRQ(ierr);
1109   } else if (isglvis) {
1110     ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr);
1111   } else {
1112     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1113   }
1114   /* Optionally view the partition */
1115   ierr = PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);CHKERRQ(ierr);
1116   if (flg) {
1117     Vec ranks;
1118     ierr = DMPlexCreateRankField(dm, &ranks);CHKERRQ(ierr);
1119     ierr = VecView(ranks, viewer);CHKERRQ(ierr);
1120     ierr = VecDestroy(&ranks);CHKERRQ(ierr);
1121   }
1122   PetscFunctionReturn(0);
1123 }
1124 
1125 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1126 {
1127   PetscBool      ishdf5;
1128   PetscErrorCode ierr;
1129 
1130   PetscFunctionBegin;
1131   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1132   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1133   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);CHKERRQ(ierr);
1134   if (ishdf5) {
1135 #if defined(PETSC_HAVE_HDF5)
1136     PetscViewerFormat format;
1137     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1138     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1139       ierr = DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);CHKERRQ(ierr);
1140     } else {
1141       ierr = DMPlexLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1142     }
1143 #else
1144     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1145 #endif
1146   } else {
1147     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1148   }
1149   PetscFunctionReturn(0);
1150 }
1151 
1152 PetscErrorCode DMDestroy_Plex(DM dm)
1153 {
1154   DM_Plex       *mesh = (DM_Plex*) dm->data;
1155   PetscErrorCode ierr;
1156 
1157   PetscFunctionBegin;
1158   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);CHKERRQ(ierr);
1159   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);CHKERRQ(ierr);
1160   if (--mesh->refct > 0) PetscFunctionReturn(0);
1161   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
1162   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
1163   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
1164   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
1165   ierr = PetscSectionDestroy(&mesh->subdomainSection);CHKERRQ(ierr);
1166   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
1167   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
1168   ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr);
1169   ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr);
1170   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
1171   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
1172   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
1173   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
1174   ierr = PetscSectionDestroy(&mesh->anchorSection);CHKERRQ(ierr);
1175   ierr = ISDestroy(&mesh->anchorIS);CHKERRQ(ierr);
1176   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
1177   ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
1178   ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
1179   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
1180   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
1181   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
1182   ierr = PetscGridHashDestroy(&mesh->lbox);CHKERRQ(ierr);
1183   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1184   ierr = PetscFree(mesh);CHKERRQ(ierr);
1185   PetscFunctionReturn(0);
1186 }
1187 
1188 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1189 {
1190   PetscSection           sectionGlobal;
1191   PetscInt               bs = -1, mbs;
1192   PetscInt               localSize;
1193   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1194   PetscErrorCode         ierr;
1195   MatType                mtype;
1196   ISLocalToGlobalMapping ltog;
1197 
1198   PetscFunctionBegin;
1199   ierr = MatInitializePackage();CHKERRQ(ierr);
1200   mtype = dm->mattype;
1201   ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1202   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
1203   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
1204   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
1205   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1206   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
1207   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
1208   ierr = MatGetBlockSize(*J, &mbs);CHKERRQ(ierr);
1209   if (mbs > 1) bs = mbs;
1210   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
1211   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
1212   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
1213   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
1214   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
1215   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
1216   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
1217   ierr = PetscStrcmp(mtype, MATIS, &isMatIS);CHKERRQ(ierr);
1218   if (!isShell) {
1219     PetscSection subSection;
1220     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1221     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1222     PetscInt     pStart, pEnd, p, dof, cdof;
1223 
1224     /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
1225     if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
1226       PetscSection section;
1227       PetscInt     size;
1228 
1229       ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
1230       ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
1231       ierr = PetscMalloc1(size,&ltogidx);CHKERRQ(ierr);
1232       ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr);
1233     } else {
1234       ierr = DMGetLocalToGlobalMapping(dm,&ltog);CHKERRQ(ierr);
1235     }
1236     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1237     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1238       PetscInt bdof;
1239 
1240       ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
1241       ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
1242       dof  = dof < 0 ? -(dof+1) : dof;
1243       bdof = cdof && (dof-cdof) ? 1 : dof;
1244       if (dof) {
1245         if (bs < 0)          {bs = bdof;}
1246         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1247       }
1248       if (isMatIS) {
1249         PetscInt loff,c,off;
1250         ierr = PetscSectionGetOffset(subSection, p, &loff);CHKERRQ(ierr);
1251         ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr);
1252         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1253       }
1254     }
1255     /* Must have same blocksize on all procs (some might have no points) */
1256     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1257     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
1258     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1259     else                            {bs = bsMinMax[0];}
1260     bs = bs < 0 ? 1 : bs;
1261     if (isMatIS) {
1262       PetscInt l;
1263       /* Must reduce indices by blocksize */
1264       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1265       ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);CHKERRQ(ierr);
1266     }
1267     ierr = MatSetLocalToGlobalMapping(*J,ltog,ltog);CHKERRQ(ierr);
1268     if (isMatIS) {
1269       ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
1270     }
1271     ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr);
1272     ierr = DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1273     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1274   }
1275   ierr = MatSetDM(*J, dm);CHKERRQ(ierr);
1276   PetscFunctionReturn(0);
1277 }
1278 
1279 /*@
1280   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
1281 
1282   Not collective
1283 
1284   Input Parameter:
1285 . mesh - The DMPlex
1286 
1287   Output Parameters:
1288 . subsection - The subdomain section
1289 
1290   Level: developer
1291 
1292 .seealso:
1293 @*/
1294 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1295 {
1296   DM_Plex       *mesh = (DM_Plex*) dm->data;
1297   PetscErrorCode ierr;
1298 
1299   PetscFunctionBegin;
1300   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1301   if (!mesh->subdomainSection) {
1302     PetscSection section;
1303     PetscSF      sf;
1304 
1305     ierr = PetscSFCreate(PETSC_COMM_SELF,&sf);CHKERRQ(ierr);
1306     ierr = DMGetSection(dm,&section);CHKERRQ(ierr);
1307     ierr = PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);CHKERRQ(ierr);
1308     ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
1309   }
1310   *subsection = mesh->subdomainSection;
1311   PetscFunctionReturn(0);
1312 }
1313 
1314 /*@
1315   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1316 
1317   Not collective
1318 
1319   Input Parameter:
1320 . mesh - The DMPlex
1321 
1322   Output Parameters:
1323 + pStart - The first mesh point
1324 - pEnd   - The upper bound for mesh points
1325 
1326   Level: beginner
1327 
1328 .seealso: DMPlexCreate(), DMPlexSetChart()
1329 @*/
1330 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1331 {
1332   DM_Plex       *mesh = (DM_Plex*) dm->data;
1333   PetscErrorCode ierr;
1334 
1335   PetscFunctionBegin;
1336   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1337   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1338   PetscFunctionReturn(0);
1339 }
1340 
1341 /*@
1342   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1343 
1344   Not collective
1345 
1346   Input Parameters:
1347 + mesh - The DMPlex
1348 . pStart - The first mesh point
1349 - pEnd   - The upper bound for mesh points
1350 
1351   Output Parameters:
1352 
1353   Level: beginner
1354 
1355 .seealso: DMPlexCreate(), DMPlexGetChart()
1356 @*/
1357 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1358 {
1359   DM_Plex       *mesh = (DM_Plex*) dm->data;
1360   PetscErrorCode ierr;
1361 
1362   PetscFunctionBegin;
1363   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1364   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1365   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1366   PetscFunctionReturn(0);
1367 }
1368 
1369 /*@
1370   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
1371 
1372   Not collective
1373 
1374   Input Parameters:
1375 + mesh - The DMPlex
1376 - p - The point, which must lie in the chart set with DMPlexSetChart()
1377 
1378   Output Parameter:
1379 . size - The cone size for point p
1380 
1381   Level: beginner
1382 
1383 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1384 @*/
1385 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1386 {
1387   DM_Plex       *mesh = (DM_Plex*) dm->data;
1388   PetscErrorCode ierr;
1389 
1390   PetscFunctionBegin;
1391   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1392   PetscValidPointer(size, 3);
1393   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1394   PetscFunctionReturn(0);
1395 }
1396 
1397 /*@
1398   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
1399 
1400   Not collective
1401 
1402   Input Parameters:
1403 + mesh - The DMPlex
1404 . p - The point, which must lie in the chart set with DMPlexSetChart()
1405 - size - The cone size for point p
1406 
1407   Output Parameter:
1408 
1409   Note:
1410   This should be called after DMPlexSetChart().
1411 
1412   Level: beginner
1413 
1414 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1415 @*/
1416 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1417 {
1418   DM_Plex       *mesh = (DM_Plex*) dm->data;
1419   PetscErrorCode ierr;
1420 
1421   PetscFunctionBegin;
1422   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1423   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1424 
1425   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1426   PetscFunctionReturn(0);
1427 }
1428 
1429 /*@
1430   DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
1431 
1432   Not collective
1433 
1434   Input Parameters:
1435 + mesh - The DMPlex
1436 . p - The point, which must lie in the chart set with DMPlexSetChart()
1437 - size - The additional cone size for point p
1438 
1439   Output Parameter:
1440 
1441   Note:
1442   This should be called after DMPlexSetChart().
1443 
1444   Level: beginner
1445 
1446 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1447 @*/
1448 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1449 {
1450   DM_Plex       *mesh = (DM_Plex*) dm->data;
1451   PetscInt       csize;
1452   PetscErrorCode ierr;
1453 
1454   PetscFunctionBegin;
1455   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1456   ierr = PetscSectionAddDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1457   ierr = PetscSectionGetDof(mesh->coneSection, p, &csize);CHKERRQ(ierr);
1458 
1459   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1460   PetscFunctionReturn(0);
1461 }
1462 
1463 /*@C
1464   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
1465 
1466   Not collective
1467 
1468   Input Parameters:
1469 + dm - The DMPlex
1470 - p - The point, which must lie in the chart set with DMPlexSetChart()
1471 
1472   Output Parameter:
1473 . cone - An array of points which are on the in-edges for point p
1474 
1475   Level: beginner
1476 
1477   Fortran Notes:
1478   Since it returns an array, this routine is only available in Fortran 90, and you must
1479   include petsc.h90 in your code.
1480 
1481 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1482 @*/
1483 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1484 {
1485   DM_Plex       *mesh = (DM_Plex*) dm->data;
1486   PetscInt       off;
1487   PetscErrorCode ierr;
1488 
1489   PetscFunctionBegin;
1490   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1491   PetscValidPointer(cone, 3);
1492   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1493   *cone = &mesh->cones[off];
1494   PetscFunctionReturn(0);
1495 }
1496 
1497 /*@
1498   DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point
1499 
1500   Not collective
1501 
1502   Input Parameters:
1503 + mesh - The DMPlex
1504 . p - The point, which must lie in the chart set with DMPlexSetChart()
1505 - cone - An array of points which are on the in-edges for point p
1506 
1507   Output Parameter:
1508 
1509   Note:
1510   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1511 
1512   Developer Note: Why not call this DMPlexSetCover()
1513 
1514   Level: beginner
1515 
1516 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1517 @*/
1518 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1519 {
1520   DM_Plex       *mesh = (DM_Plex*) dm->data;
1521   PetscInt       pStart, pEnd;
1522   PetscInt       dof, off, c;
1523   PetscErrorCode ierr;
1524 
1525   PetscFunctionBegin;
1526   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1527   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1528   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1529   if (dof) PetscValidPointer(cone, 3);
1530   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1531   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);
1532   for (c = 0; c < dof; ++c) {
1533     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);
1534     mesh->cones[off+c] = cone[c];
1535   }
1536   PetscFunctionReturn(0);
1537 }
1538 
1539 /*@C
1540   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
1541 
1542   Not collective
1543 
1544   Input Parameters:
1545 + mesh - The DMPlex
1546 - p - The point, which must lie in the chart set with DMPlexSetChart()
1547 
1548   Output Parameter:
1549 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1550                     integer giving the prescription for cone traversal. If it is negative, the cone is
1551                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1552                     the index of the cone point on which to start.
1553 
1554   Level: beginner
1555 
1556   Fortran Notes:
1557   Since it returns an array, this routine is only available in Fortran 90, and you must
1558   include petsc.h90 in your code.
1559 
1560   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1561 
1562 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1563 @*/
1564 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1565 {
1566   DM_Plex       *mesh = (DM_Plex*) dm->data;
1567   PetscInt       off;
1568   PetscErrorCode ierr;
1569 
1570   PetscFunctionBegin;
1571   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1572 #if defined(PETSC_USE_DEBUG)
1573   {
1574     PetscInt dof;
1575     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1576     if (dof) PetscValidPointer(coneOrientation, 3);
1577   }
1578 #endif
1579   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1580 
1581   *coneOrientation = &mesh->coneOrientations[off];
1582   PetscFunctionReturn(0);
1583 }
1584 
1585 /*@
1586   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
1587 
1588   Not collective
1589 
1590   Input Parameters:
1591 + mesh - The DMPlex
1592 . p - The point, which must lie in the chart set with DMPlexSetChart()
1593 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1594                     integer giving the prescription for cone traversal. If it is negative, the cone is
1595                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1596                     the index of the cone point on which to start.
1597 
1598   Output Parameter:
1599 
1600   Note:
1601   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1602 
1603   Level: beginner
1604 
1605 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1606 @*/
1607 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1608 {
1609   DM_Plex       *mesh = (DM_Plex*) dm->data;
1610   PetscInt       pStart, pEnd;
1611   PetscInt       dof, off, c;
1612   PetscErrorCode ierr;
1613 
1614   PetscFunctionBegin;
1615   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1616   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1617   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1618   if (dof) PetscValidPointer(coneOrientation, 3);
1619   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1620   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);
1621   for (c = 0; c < dof; ++c) {
1622     PetscInt cdof, o = coneOrientation[c];
1623 
1624     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1625     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);
1626     mesh->coneOrientations[off+c] = o;
1627   }
1628   PetscFunctionReturn(0);
1629 }
1630 
1631 /*@
1632   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
1633 
1634   Not collective
1635 
1636   Input Parameters:
1637 + mesh - The DMPlex
1638 . p - The point, which must lie in the chart set with DMPlexSetChart()
1639 . conePos - The local index in the cone where the point should be put
1640 - conePoint - The mesh point to insert
1641 
1642   Level: beginner
1643 
1644 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1645 @*/
1646 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1647 {
1648   DM_Plex       *mesh = (DM_Plex*) dm->data;
1649   PetscInt       pStart, pEnd;
1650   PetscInt       dof, off;
1651   PetscErrorCode ierr;
1652 
1653   PetscFunctionBegin;
1654   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1655   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1656   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);
1657   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);
1658   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1659   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1660   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);
1661   mesh->cones[off+conePos] = conePoint;
1662   PetscFunctionReturn(0);
1663 }
1664 
1665 /*@
1666   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
1667 
1668   Not collective
1669 
1670   Input Parameters:
1671 + mesh - The DMPlex
1672 . p - The point, which must lie in the chart set with DMPlexSetChart()
1673 . conePos - The local index in the cone where the point should be put
1674 - coneOrientation - The point orientation to insert
1675 
1676   Level: beginner
1677 
1678 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1679 @*/
1680 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1681 {
1682   DM_Plex       *mesh = (DM_Plex*) dm->data;
1683   PetscInt       pStart, pEnd;
1684   PetscInt       dof, off;
1685   PetscErrorCode ierr;
1686 
1687   PetscFunctionBegin;
1688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1689   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1690   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);
1691   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1692   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1693   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);
1694   mesh->coneOrientations[off+conePos] = coneOrientation;
1695   PetscFunctionReturn(0);
1696 }
1697 
1698 /*@
1699   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
1700 
1701   Not collective
1702 
1703   Input Parameters:
1704 + mesh - The DMPlex
1705 - p - The point, which must lie in the chart set with DMPlexSetChart()
1706 
1707   Output Parameter:
1708 . size - The support size for point p
1709 
1710   Level: beginner
1711 
1712 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1713 @*/
1714 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1715 {
1716   DM_Plex       *mesh = (DM_Plex*) dm->data;
1717   PetscErrorCode ierr;
1718 
1719   PetscFunctionBegin;
1720   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1721   PetscValidPointer(size, 3);
1722   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1723   PetscFunctionReturn(0);
1724 }
1725 
1726 /*@
1727   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
1728 
1729   Not collective
1730 
1731   Input Parameters:
1732 + mesh - The DMPlex
1733 . p - The point, which must lie in the chart set with DMPlexSetChart()
1734 - size - The support size for point p
1735 
1736   Output Parameter:
1737 
1738   Note:
1739   This should be called after DMPlexSetChart().
1740 
1741   Level: beginner
1742 
1743 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1744 @*/
1745 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1746 {
1747   DM_Plex       *mesh = (DM_Plex*) dm->data;
1748   PetscErrorCode ierr;
1749 
1750   PetscFunctionBegin;
1751   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1752   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1753 
1754   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1755   PetscFunctionReturn(0);
1756 }
1757 
1758 /*@C
1759   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
1760 
1761   Not collective
1762 
1763   Input Parameters:
1764 + mesh - The DMPlex
1765 - p - The point, which must lie in the chart set with DMPlexSetChart()
1766 
1767   Output Parameter:
1768 . support - An array of points which are on the out-edges for point p
1769 
1770   Level: beginner
1771 
1772   Fortran Notes:
1773   Since it returns an array, this routine is only available in Fortran 90, and you must
1774   include petsc.h90 in your code.
1775 
1776   You must also call DMPlexRestoreSupport() after you finish using the returned array.
1777 
1778 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1779 @*/
1780 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1781 {
1782   DM_Plex       *mesh = (DM_Plex*) dm->data;
1783   PetscInt       off;
1784   PetscErrorCode ierr;
1785 
1786   PetscFunctionBegin;
1787   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1788   PetscValidPointer(support, 3);
1789   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1790   *support = &mesh->supports[off];
1791   PetscFunctionReturn(0);
1792 }
1793 
1794 /*@
1795   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
1796 
1797   Not collective
1798 
1799   Input Parameters:
1800 + mesh - The DMPlex
1801 . p - The point, which must lie in the chart set with DMPlexSetChart()
1802 - support - An array of points which are on the out-edges for point p
1803 
1804   Output Parameter:
1805 
1806   Note:
1807   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1808 
1809   Level: beginner
1810 
1811 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1812 @*/
1813 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1814 {
1815   DM_Plex       *mesh = (DM_Plex*) dm->data;
1816   PetscInt       pStart, pEnd;
1817   PetscInt       dof, off, c;
1818   PetscErrorCode ierr;
1819 
1820   PetscFunctionBegin;
1821   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1822   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1823   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1824   if (dof) PetscValidPointer(support, 3);
1825   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1826   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);
1827   for (c = 0; c < dof; ++c) {
1828     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);
1829     mesh->supports[off+c] = support[c];
1830   }
1831   PetscFunctionReturn(0);
1832 }
1833 
1834 /*@
1835   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
1836 
1837   Not collective
1838 
1839   Input Parameters:
1840 + mesh - The DMPlex
1841 . p - The point, which must lie in the chart set with DMPlexSetChart()
1842 . supportPos - The local index in the cone where the point should be put
1843 - supportPoint - The mesh point to insert
1844 
1845   Level: beginner
1846 
1847 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1848 @*/
1849 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1850 {
1851   DM_Plex       *mesh = (DM_Plex*) dm->data;
1852   PetscInt       pStart, pEnd;
1853   PetscInt       dof, off;
1854   PetscErrorCode ierr;
1855 
1856   PetscFunctionBegin;
1857   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1858   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1859   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1860   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1861   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);
1862   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);
1863   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);
1864   mesh->supports[off+supportPos] = supportPoint;
1865   PetscFunctionReturn(0);
1866 }
1867 
1868 /*@C
1869   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
1870 
1871   Not collective
1872 
1873   Input Parameters:
1874 + mesh - The DMPlex
1875 . p - The point, which must lie in the chart set with DMPlexSetChart()
1876 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1877 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1878 
1879   Output Parameters:
1880 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1881 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1882 
1883   Note:
1884   If using internal storage (points is NULL on input), each call overwrites the last output.
1885 
1886   Fortran Notes:
1887   Since it returns an array, this routine is only available in Fortran 90, and you must
1888   include petsc.h90 in your code.
1889 
1890   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1891 
1892   Level: beginner
1893 
1894 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1895 @*/
1896 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1897 {
1898   DM_Plex        *mesh = (DM_Plex*) dm->data;
1899   PetscInt       *closure, *fifo;
1900   const PetscInt *tmp = NULL, *tmpO = NULL;
1901   PetscInt        tmpSize, t;
1902   PetscInt        depth       = 0, maxSize;
1903   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1904   PetscErrorCode  ierr;
1905 
1906   PetscFunctionBegin;
1907   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1908   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1909   /* This is only 1-level */
1910   if (useCone) {
1911     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1912     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1913     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1914   } else {
1915     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1916     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1917   }
1918   if (depth == 1) {
1919     if (*points) {
1920       closure = *points;
1921     } else {
1922       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1923       ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
1924     }
1925     closure[0] = p; closure[1] = 0;
1926     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1927       closure[closureSize]   = tmp[t];
1928       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1929     }
1930     if (numPoints) *numPoints = closureSize/2;
1931     if (points)    *points    = closure;
1932     PetscFunctionReturn(0);
1933   }
1934   {
1935     PetscInt c, coneSeries, s,supportSeries;
1936 
1937     c = mesh->maxConeSize;
1938     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1939     s = mesh->maxSupportSize;
1940     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1941     maxSize = 2*PetscMax(coneSeries,supportSeries);
1942   }
1943   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
1944   if (*points) {
1945     closure = *points;
1946   } else {
1947     ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
1948   }
1949   closure[0] = p; closure[1] = 0;
1950   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1951     const PetscInt cp = tmp[t];
1952     const PetscInt co = tmpO ? tmpO[t] : 0;
1953 
1954     closure[closureSize]   = cp;
1955     closure[closureSize+1] = co;
1956     fifo[fifoSize]         = cp;
1957     fifo[fifoSize+1]       = co;
1958   }
1959   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1960   while (fifoSize - fifoStart) {
1961     const PetscInt q   = fifo[fifoStart];
1962     const PetscInt o   = fifo[fifoStart+1];
1963     const PetscInt rev = o >= 0 ? 0 : 1;
1964     const PetscInt off = rev ? -(o+1) : o;
1965 
1966     if (useCone) {
1967       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1968       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1969       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1970     } else {
1971       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1972       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1973       tmpO = NULL;
1974     }
1975     for (t = 0; t < tmpSize; ++t) {
1976       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1977       const PetscInt cp = tmp[i];
1978       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1979       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1980        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1981       PetscInt       co = tmpO ? tmpO[i] : 0;
1982       PetscInt       c;
1983 
1984       if (rev) {
1985         PetscInt childSize, coff;
1986         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1987         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1988         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1989       }
1990       /* Check for duplicate */
1991       for (c = 0; c < closureSize; c += 2) {
1992         if (closure[c] == cp) break;
1993       }
1994       if (c == closureSize) {
1995         closure[closureSize]   = cp;
1996         closure[closureSize+1] = co;
1997         fifo[fifoSize]         = cp;
1998         fifo[fifoSize+1]       = co;
1999         closureSize           += 2;
2000         fifoSize              += 2;
2001       }
2002     }
2003     fifoStart += 2;
2004   }
2005   if (numPoints) *numPoints = closureSize/2;
2006   if (points)    *points    = closure;
2007   ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
2008   PetscFunctionReturn(0);
2009 }
2010 
2011 /*@C
2012   DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG with a specified initial orientation
2013 
2014   Not collective
2015 
2016   Input Parameters:
2017 + mesh - The DMPlex
2018 . p - The point, which must lie in the chart set with DMPlexSetChart()
2019 . orientation - The orientation of the point
2020 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2021 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2022 
2023   Output Parameters:
2024 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2025 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2026 
2027   Note:
2028   If using internal storage (points is NULL on input), each call overwrites the last output.
2029 
2030   Fortran Notes:
2031   Since it returns an array, this routine is only available in Fortran 90, and you must
2032   include petsc.h90 in your code.
2033 
2034   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2035 
2036   Level: beginner
2037 
2038 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2039 @*/
2040 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2041 {
2042   DM_Plex        *mesh = (DM_Plex*) dm->data;
2043   PetscInt       *closure, *fifo;
2044   const PetscInt *tmp = NULL, *tmpO = NULL;
2045   PetscInt        tmpSize, t;
2046   PetscInt        depth       = 0, maxSize;
2047   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2048   PetscErrorCode  ierr;
2049 
2050   PetscFunctionBegin;
2051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2052   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2053   /* This is only 1-level */
2054   if (useCone) {
2055     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
2056     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
2057     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
2058   } else {
2059     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
2060     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
2061   }
2062   if (depth == 1) {
2063     if (*points) {
2064       closure = *points;
2065     } else {
2066       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2067       ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
2068     }
2069     closure[0] = p; closure[1] = ornt;
2070     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2071       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2072       closure[closureSize]   = tmp[i];
2073       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2074     }
2075     if (numPoints) *numPoints = closureSize/2;
2076     if (points)    *points    = closure;
2077     PetscFunctionReturn(0);
2078   }
2079   {
2080     PetscInt c, coneSeries, s,supportSeries;
2081 
2082     c = mesh->maxConeSize;
2083     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2084     s = mesh->maxSupportSize;
2085     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2086     maxSize = 2*PetscMax(coneSeries,supportSeries);
2087   }
2088   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
2089   if (*points) {
2090     closure = *points;
2091   } else {
2092     ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
2093   }
2094   closure[0] = p; closure[1] = ornt;
2095   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2096     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2097     const PetscInt cp = tmp[i];
2098     PetscInt       co = tmpO ? tmpO[i] : 0;
2099 
2100     if (ornt < 0) {
2101       PetscInt childSize, coff;
2102       ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
2103       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2104       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2105     }
2106     closure[closureSize]   = cp;
2107     closure[closureSize+1] = co;
2108     fifo[fifoSize]         = cp;
2109     fifo[fifoSize+1]       = co;
2110   }
2111   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2112   while (fifoSize - fifoStart) {
2113     const PetscInt q   = fifo[fifoStart];
2114     const PetscInt o   = fifo[fifoStart+1];
2115     const PetscInt rev = o >= 0 ? 0 : 1;
2116     const PetscInt off = rev ? -(o+1) : o;
2117 
2118     if (useCone) {
2119       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
2120       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
2121       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
2122     } else {
2123       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
2124       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
2125       tmpO = NULL;
2126     }
2127     for (t = 0; t < tmpSize; ++t) {
2128       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2129       const PetscInt cp = tmp[i];
2130       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2131       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2132        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2133       PetscInt       co = tmpO ? tmpO[i] : 0;
2134       PetscInt       c;
2135 
2136       if (rev) {
2137         PetscInt childSize, coff;
2138         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
2139         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2140         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2141       }
2142       /* Check for duplicate */
2143       for (c = 0; c < closureSize; c += 2) {
2144         if (closure[c] == cp) break;
2145       }
2146       if (c == closureSize) {
2147         closure[closureSize]   = cp;
2148         closure[closureSize+1] = co;
2149         fifo[fifoSize]         = cp;
2150         fifo[fifoSize+1]       = co;
2151         closureSize           += 2;
2152         fifoSize              += 2;
2153       }
2154     }
2155     fifoStart += 2;
2156   }
2157   if (numPoints) *numPoints = closureSize/2;
2158   if (points)    *points    = closure;
2159   ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
2160   PetscFunctionReturn(0);
2161 }
2162 
2163 /*@C
2164   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
2165 
2166   Not collective
2167 
2168   Input Parameters:
2169 + mesh - The DMPlex
2170 . p - The point, which must lie in the chart set with DMPlexSetChart()
2171 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2172 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
2173 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
2174 
2175   Note:
2176   If not using internal storage (points is not NULL on input), this call is unnecessary
2177 
2178   Fortran Notes:
2179   Since it returns an array, this routine is only available in Fortran 90, and you must
2180   include petsc.h90 in your code.
2181 
2182   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2183 
2184   Level: beginner
2185 
2186 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2187 @*/
2188 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2189 {
2190   PetscErrorCode ierr;
2191 
2192   PetscFunctionBegin;
2193   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2194   if (numPoints) PetscValidIntPointer(numPoints,4);
2195   if (points) PetscValidPointer(points,5);
2196   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, points);CHKERRQ(ierr);
2197   if (numPoints) *numPoints = 0;
2198   PetscFunctionReturn(0);
2199 }
2200 
2201 /*@
2202   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
2203 
2204   Not collective
2205 
2206   Input Parameter:
2207 . mesh - The DMPlex
2208 
2209   Output Parameters:
2210 + maxConeSize - The maximum number of in-edges
2211 - maxSupportSize - The maximum number of out-edges
2212 
2213   Level: beginner
2214 
2215 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2216 @*/
2217 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2218 {
2219   DM_Plex *mesh = (DM_Plex*) dm->data;
2220 
2221   PetscFunctionBegin;
2222   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2223   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2224   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2225   PetscFunctionReturn(0);
2226 }
2227 
2228 PetscErrorCode DMSetUp_Plex(DM dm)
2229 {
2230   DM_Plex       *mesh = (DM_Plex*) dm->data;
2231   PetscInt       size;
2232   PetscErrorCode ierr;
2233 
2234   PetscFunctionBegin;
2235   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2236   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
2237   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
2238   ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr);
2239   ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr);
2240   if (mesh->maxSupportSize) {
2241     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
2242     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
2243     ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr);
2244   }
2245   PetscFunctionReturn(0);
2246 }
2247 
2248 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2249 {
2250   PetscErrorCode ierr;
2251 
2252   PetscFunctionBegin;
2253   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
2254   ierr = DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
2255   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2256   if (dm->useNatural && dm->sfMigration) {
2257     PetscSF        sfMigrationInv,sfNatural;
2258     PetscSection   section, sectionSeq;
2259 
2260     (*subdm)->sfMigration = dm->sfMigration;
2261     ierr = PetscObjectReference((PetscObject) dm->sfMigration);CHKERRQ(ierr);
2262     ierr = DMGetSection((*subdm), &section);CHKERRQ(ierr);CHKERRQ(ierr);
2263     ierr = PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
2264     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);CHKERRQ(ierr);
2265     ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
2266 
2267     ierr = DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
2268     (*subdm)->sfNatural = sfNatural;
2269     ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
2270     ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
2271   }
2272   PetscFunctionReturn(0);
2273 }
2274 
2275 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2276 {
2277   PetscErrorCode ierr;
2278   PetscInt       i = 0;
2279 
2280   PetscFunctionBegin;
2281   if (superdm) {ierr = DMClone(dms[0], superdm);CHKERRQ(ierr);}
2282   ierr = DMCreateSuperDM_Section_Private(dms, len, is, superdm);CHKERRQ(ierr);
2283   (*superdm)->useNatural = PETSC_FALSE;
2284   for (i = 0; i < len; i++){
2285     if (dms[i]->useNatural && dms[i]->sfMigration) {
2286       PetscSF        sfMigrationInv,sfNatural;
2287       PetscSection   section, sectionSeq;
2288 
2289       (*superdm)->sfMigration = dms[i]->sfMigration;
2290       ierr = PetscObjectReference((PetscObject) dms[i]->sfMigration);CHKERRQ(ierr);
2291       (*superdm)->useNatural = PETSC_TRUE;
2292       ierr = DMGetSection((*superdm), &section);CHKERRQ(ierr);
2293       ierr = PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
2294       ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);CHKERRQ(ierr);
2295       ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
2296 
2297       ierr = DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
2298       (*superdm)->sfNatural = sfNatural;
2299       ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
2300       ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
2301       break;
2302     }
2303   }
2304   PetscFunctionReturn(0);
2305 }
2306 
2307 /*@
2308   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
2309 
2310   Not collective
2311 
2312   Input Parameter:
2313 . mesh - The DMPlex
2314 
2315   Output Parameter:
2316 
2317   Note:
2318   This should be called after all calls to DMPlexSetCone()
2319 
2320   Level: beginner
2321 
2322 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2323 @*/
2324 PetscErrorCode DMPlexSymmetrize(DM dm)
2325 {
2326   DM_Plex       *mesh = (DM_Plex*) dm->data;
2327   PetscInt      *offsets;
2328   PetscInt       supportSize;
2329   PetscInt       pStart, pEnd, p;
2330   PetscErrorCode ierr;
2331 
2332   PetscFunctionBegin;
2333   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2334   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2335   /* Calculate support sizes */
2336   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2337   for (p = pStart; p < pEnd; ++p) {
2338     PetscInt dof, off, c;
2339 
2340     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2341     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2342     for (c = off; c < off+dof; ++c) {
2343       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
2344     }
2345   }
2346   for (p = pStart; p < pEnd; ++p) {
2347     PetscInt dof;
2348 
2349     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
2350 
2351     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2352   }
2353   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
2354   /* Calculate supports */
2355   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
2356   ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr);
2357   ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr);
2358   for (p = pStart; p < pEnd; ++p) {
2359     PetscInt dof, off, c;
2360 
2361     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2362     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2363     for (c = off; c < off+dof; ++c) {
2364       const PetscInt q = mesh->cones[c];
2365       PetscInt       offS;
2366 
2367       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
2368 
2369       mesh->supports[offS+offsets[q]] = p;
2370       ++offsets[q];
2371     }
2372   }
2373   ierr = PetscFree(offsets);CHKERRQ(ierr);
2374   PetscFunctionReturn(0);
2375 }
2376 
2377 static PetscErrorCode DMPlexCreateDimStratum(DM,DMLabel,DMLabel,PetscInt,PetscInt);
2378 
2379 /*@
2380   DMPlexStratify - The DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2381   can be illustrated by a Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2382   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2383   the DAG.
2384 
2385   Collective on dm
2386 
2387   Input Parameter:
2388 . mesh - The DMPlex
2389 
2390   Output Parameter:
2391 
2392   Notes:
2393   Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
2394   1 for edges, and so on.  The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2395   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
2396   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
2397 
2398   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
2399 
2400   Level: beginner
2401 
2402 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2403 @*/
2404 PetscErrorCode DMPlexStratify(DM dm)
2405 {
2406   DM_Plex       *mesh = (DM_Plex*) dm->data;
2407   DMLabel        label;
2408   PetscInt       pStart, pEnd, p;
2409   PetscInt       numRoots = 0, numLeaves = 0;
2410   PetscInt       cMax, fMax, eMax, vMax;
2411   PetscErrorCode ierr;
2412 
2413   PetscFunctionBegin;
2414   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2415   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2416   /* Calculate depth */
2417   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2418   ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr);
2419   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
2420   /* Initialize roots and count leaves */
2421   for (p = pStart; p < pEnd; ++p) {
2422     PetscInt coneSize, supportSize;
2423 
2424     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2425     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2426     if (!coneSize && supportSize) {
2427       ++numRoots;
2428       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
2429     } else if (!supportSize && coneSize) {
2430       ++numLeaves;
2431     } else if (!supportSize && !coneSize) {
2432       /* Isolated points */
2433       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
2434     }
2435   }
2436   if (numRoots + numLeaves == (pEnd - pStart)) {
2437     for (p = pStart; p < pEnd; ++p) {
2438       PetscInt coneSize, supportSize;
2439 
2440       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2441       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2442       if (!supportSize && coneSize) {
2443         ierr = DMLabelSetValue(label, p, 1);CHKERRQ(ierr);
2444       }
2445     }
2446   } else {
2447     IS       pointIS;
2448     PetscInt numPoints = 0, level = 0;
2449 
2450     ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
2451     if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
2452     while (numPoints) {
2453       const PetscInt *points;
2454       const PetscInt  newLevel = level+1;
2455 
2456       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
2457       for (p = 0; p < numPoints; ++p) {
2458         const PetscInt  point = points[p];
2459         const PetscInt *support;
2460         PetscInt        supportSize, s;
2461 
2462         ierr = DMPlexGetSupportSize(dm, point, &supportSize);CHKERRQ(ierr);
2463         ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr);
2464         for (s = 0; s < supportSize; ++s) {
2465           ierr = DMLabelSetValue(label, support[s], newLevel);CHKERRQ(ierr);
2466         }
2467       }
2468       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
2469       ++level;
2470       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2471       ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
2472       if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
2473       else         {numPoints = 0;}
2474     }
2475     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2476   }
2477   { /* just in case there is an empty process */
2478     PetscInt numValues, maxValues = 0, v;
2479 
2480     ierr = DMLabelGetNumValues(label,&numValues);CHKERRQ(ierr);
2481     for (v = 0; v < numValues; v++) {
2482       IS pointIS;
2483 
2484       ierr = DMLabelGetStratumIS(label, v, &pointIS);CHKERRQ(ierr);
2485       if (pointIS) {
2486         PetscInt  min, max, numPoints;
2487         PetscInt  start;
2488         PetscBool contig;
2489 
2490         ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
2491         ierr = ISGetMinMax(pointIS, &min, &max);CHKERRQ(ierr);
2492         ierr = ISContiguousLocal(pointIS,min,max+1,&start,&contig);CHKERRQ(ierr);
2493         if (start == 0 && contig) {
2494           ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2495           ierr = ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);CHKERRQ(ierr);
2496           ierr = DMLabelSetStratumIS(label, v, pointIS);CHKERRQ(ierr);
2497         }
2498       }
2499       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2500     }
2501     ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
2502     for (v = numValues; v < maxValues; v++) {
2503       DMLabelAddStratum(label,v);CHKERRQ(ierr);
2504     }
2505   }
2506   ierr = DMLabelGetState(label, &mesh->depthState);CHKERRQ(ierr);
2507 
2508   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
2509   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2510     DMLabel  dimLabel;
2511     PetscInt dim;
2512 
2513     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
2514     ierr = DMGetLabel(dm, "dim", &dimLabel);CHKERRQ(ierr);
2515     if (!dimLabel) {
2516       ierr = DMCreateLabel(dm, "dim");CHKERRQ(ierr);
2517       ierr = DMGetLabel(dm, "dim", &dimLabel);CHKERRQ(ierr);
2518     }
2519     if (cMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);CHKERRQ(ierr);}
2520     if (fMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);CHKERRQ(ierr);}
2521     if (eMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);CHKERRQ(ierr);}
2522     if (vMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);CHKERRQ(ierr);}
2523   }
2524   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2525   PetscFunctionReturn(0);
2526 }
2527 
2528 /*@C
2529   DMPlexGetJoin - Get an array for the join of the set of points
2530 
2531   Not Collective
2532 
2533   Input Parameters:
2534 + dm - The DMPlex object
2535 . numPoints - The number of input points for the join
2536 - points - The input points
2537 
2538   Output Parameters:
2539 + numCoveredPoints - The number of points in the join
2540 - coveredPoints - The points in the join
2541 
2542   Level: intermediate
2543 
2544   Note: Currently, this is restricted to a single level join
2545 
2546   Fortran Notes:
2547   Since it returns an array, this routine is only available in Fortran 90, and you must
2548   include petsc.h90 in your code.
2549 
2550   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2551 
2552 .keywords: mesh
2553 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2554 @*/
2555 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2556 {
2557   DM_Plex       *mesh = (DM_Plex*) dm->data;
2558   PetscInt      *join[2];
2559   PetscInt       joinSize, i = 0;
2560   PetscInt       dof, off, p, c, m;
2561   PetscErrorCode ierr;
2562 
2563   PetscFunctionBegin;
2564   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2565   PetscValidPointer(points, 2);
2566   PetscValidPointer(numCoveredPoints, 3);
2567   PetscValidPointer(coveredPoints, 4);
2568   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
2569   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
2570   /* Copy in support of first point */
2571   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2572   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2573   for (joinSize = 0; joinSize < dof; ++joinSize) {
2574     join[i][joinSize] = mesh->supports[off+joinSize];
2575   }
2576   /* Check each successive support */
2577   for (p = 1; p < numPoints; ++p) {
2578     PetscInt newJoinSize = 0;
2579 
2580     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2581     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2582     for (c = 0; c < dof; ++c) {
2583       const PetscInt point = mesh->supports[off+c];
2584 
2585       for (m = 0; m < joinSize; ++m) {
2586         if (point == join[i][m]) {
2587           join[1-i][newJoinSize++] = point;
2588           break;
2589         }
2590       }
2591     }
2592     joinSize = newJoinSize;
2593     i        = 1-i;
2594   }
2595   *numCoveredPoints = joinSize;
2596   *coveredPoints    = join[i];
2597   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
2598   PetscFunctionReturn(0);
2599 }
2600 
2601 /*@C
2602   DMPlexRestoreJoin - Restore an array for the join of the set of points
2603 
2604   Not Collective
2605 
2606   Input Parameters:
2607 + dm - The DMPlex object
2608 . numPoints - The number of input points for the join
2609 - points - The input points
2610 
2611   Output Parameters:
2612 + numCoveredPoints - The number of points in the join
2613 - coveredPoints - The points in the join
2614 
2615   Fortran Notes:
2616   Since it returns an array, this routine is only available in Fortran 90, and you must
2617   include petsc.h90 in your code.
2618 
2619   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2620 
2621   Level: intermediate
2622 
2623 .keywords: mesh
2624 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2625 @*/
2626 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2627 {
2628   PetscErrorCode ierr;
2629 
2630   PetscFunctionBegin;
2631   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2632   if (points) PetscValidIntPointer(points,3);
2633   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
2634   PetscValidPointer(coveredPoints, 5);
2635   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
2636   if (numCoveredPoints) *numCoveredPoints = 0;
2637   PetscFunctionReturn(0);
2638 }
2639 
2640 /*@C
2641   DMPlexGetFullJoin - Get an array for the join of the set of points
2642 
2643   Not Collective
2644 
2645   Input Parameters:
2646 + dm - The DMPlex object
2647 . numPoints - The number of input points for the join
2648 - points - The input points
2649 
2650   Output Parameters:
2651 + numCoveredPoints - The number of points in the join
2652 - coveredPoints - The points in the join
2653 
2654   Fortran Notes:
2655   Since it returns an array, this routine is only available in Fortran 90, and you must
2656   include petsc.h90 in your code.
2657 
2658   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2659 
2660   Level: intermediate
2661 
2662 .keywords: mesh
2663 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2664 @*/
2665 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2666 {
2667   DM_Plex       *mesh = (DM_Plex*) dm->data;
2668   PetscInt      *offsets, **closures;
2669   PetscInt      *join[2];
2670   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2671   PetscInt       p, d, c, m, ms;
2672   PetscErrorCode ierr;
2673 
2674   PetscFunctionBegin;
2675   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2676   PetscValidPointer(points, 2);
2677   PetscValidPointer(numCoveredPoints, 3);
2678   PetscValidPointer(coveredPoints, 4);
2679 
2680   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2681   ierr    = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr);
2682   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
2683   ms      = mesh->maxSupportSize;
2684   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2685   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
2686   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
2687 
2688   for (p = 0; p < numPoints; ++p) {
2689     PetscInt closureSize;
2690 
2691     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2692 
2693     offsets[p*(depth+2)+0] = 0;
2694     for (d = 0; d < depth+1; ++d) {
2695       PetscInt pStart, pEnd, i;
2696 
2697       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2698       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2699         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2700           offsets[p*(depth+2)+d+1] = i;
2701           break;
2702         }
2703       }
2704       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2705     }
2706     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);
2707   }
2708   for (d = 0; d < depth+1; ++d) {
2709     PetscInt dof;
2710 
2711     /* Copy in support of first point */
2712     dof = offsets[d+1] - offsets[d];
2713     for (joinSize = 0; joinSize < dof; ++joinSize) {
2714       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2715     }
2716     /* Check each successive cone */
2717     for (p = 1; p < numPoints && joinSize; ++p) {
2718       PetscInt newJoinSize = 0;
2719 
2720       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2721       for (c = 0; c < dof; ++c) {
2722         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2723 
2724         for (m = 0; m < joinSize; ++m) {
2725           if (point == join[i][m]) {
2726             join[1-i][newJoinSize++] = point;
2727             break;
2728           }
2729         }
2730       }
2731       joinSize = newJoinSize;
2732       i        = 1-i;
2733     }
2734     if (joinSize) break;
2735   }
2736   *numCoveredPoints = joinSize;
2737   *coveredPoints    = join[i];
2738   for (p = 0; p < numPoints; ++p) {
2739     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2740   }
2741   ierr = PetscFree(closures);CHKERRQ(ierr);
2742   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
2743   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
2744   PetscFunctionReturn(0);
2745 }
2746 
2747 /*@C
2748   DMPlexGetMeet - Get an array for the meet of the set of points
2749 
2750   Not Collective
2751 
2752   Input Parameters:
2753 + dm - The DMPlex object
2754 . numPoints - The number of input points for the meet
2755 - points - The input points
2756 
2757   Output Parameters:
2758 + numCoveredPoints - The number of points in the meet
2759 - coveredPoints - The points in the meet
2760 
2761   Level: intermediate
2762 
2763   Note: Currently, this is restricted to a single level meet
2764 
2765   Fortran Notes:
2766   Since it returns an array, this routine is only available in Fortran 90, and you must
2767   include petsc.h90 in your code.
2768 
2769   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2770 
2771 .keywords: mesh
2772 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2773 @*/
2774 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2775 {
2776   DM_Plex       *mesh = (DM_Plex*) dm->data;
2777   PetscInt      *meet[2];
2778   PetscInt       meetSize, i = 0;
2779   PetscInt       dof, off, p, c, m;
2780   PetscErrorCode ierr;
2781 
2782   PetscFunctionBegin;
2783   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2784   PetscValidPointer(points, 2);
2785   PetscValidPointer(numCoveringPoints, 3);
2786   PetscValidPointer(coveringPoints, 4);
2787   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
2788   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
2789   /* Copy in cone of first point */
2790   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2791   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2792   for (meetSize = 0; meetSize < dof; ++meetSize) {
2793     meet[i][meetSize] = mesh->cones[off+meetSize];
2794   }
2795   /* Check each successive cone */
2796   for (p = 1; p < numPoints; ++p) {
2797     PetscInt newMeetSize = 0;
2798 
2799     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2800     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2801     for (c = 0; c < dof; ++c) {
2802       const PetscInt point = mesh->cones[off+c];
2803 
2804       for (m = 0; m < meetSize; ++m) {
2805         if (point == meet[i][m]) {
2806           meet[1-i][newMeetSize++] = point;
2807           break;
2808         }
2809       }
2810     }
2811     meetSize = newMeetSize;
2812     i        = 1-i;
2813   }
2814   *numCoveringPoints = meetSize;
2815   *coveringPoints    = meet[i];
2816   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
2817   PetscFunctionReturn(0);
2818 }
2819 
2820 /*@C
2821   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2822 
2823   Not Collective
2824 
2825   Input Parameters:
2826 + dm - The DMPlex object
2827 . numPoints - The number of input points for the meet
2828 - points - The input points
2829 
2830   Output Parameters:
2831 + numCoveredPoints - The number of points in the meet
2832 - coveredPoints - The points in the meet
2833 
2834   Level: intermediate
2835 
2836   Fortran Notes:
2837   Since it returns an array, this routine is only available in Fortran 90, and you must
2838   include petsc.h90 in your code.
2839 
2840   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2841 
2842 .keywords: mesh
2843 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2844 @*/
2845 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2846 {
2847   PetscErrorCode ierr;
2848 
2849   PetscFunctionBegin;
2850   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2851   if (points) PetscValidIntPointer(points,3);
2852   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
2853   PetscValidPointer(coveredPoints,5);
2854   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
2855   if (numCoveredPoints) *numCoveredPoints = 0;
2856   PetscFunctionReturn(0);
2857 }
2858 
2859 /*@C
2860   DMPlexGetFullMeet - Get an array for the meet of the set of points
2861 
2862   Not Collective
2863 
2864   Input Parameters:
2865 + dm - The DMPlex object
2866 . numPoints - The number of input points for the meet
2867 - points - The input points
2868 
2869   Output Parameters:
2870 + numCoveredPoints - The number of points in the meet
2871 - coveredPoints - The points in the meet
2872 
2873   Level: intermediate
2874 
2875   Fortran Notes:
2876   Since it returns an array, this routine is only available in Fortran 90, and you must
2877   include petsc.h90 in your code.
2878 
2879   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2880 
2881 .keywords: mesh
2882 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2883 @*/
2884 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2885 {
2886   DM_Plex       *mesh = (DM_Plex*) dm->data;
2887   PetscInt      *offsets, **closures;
2888   PetscInt      *meet[2];
2889   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2890   PetscInt       p, h, c, m, mc;
2891   PetscErrorCode ierr;
2892 
2893   PetscFunctionBegin;
2894   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2895   PetscValidPointer(points, 2);
2896   PetscValidPointer(numCoveredPoints, 3);
2897   PetscValidPointer(coveredPoints, 4);
2898 
2899   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2900   ierr    = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr);
2901   ierr    = DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
2902   mc      = mesh->maxConeSize;
2903   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2904   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
2905   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
2906 
2907   for (p = 0; p < numPoints; ++p) {
2908     PetscInt closureSize;
2909 
2910     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2911 
2912     offsets[p*(height+2)+0] = 0;
2913     for (h = 0; h < height+1; ++h) {
2914       PetscInt pStart, pEnd, i;
2915 
2916       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2917       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2918         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2919           offsets[p*(height+2)+h+1] = i;
2920           break;
2921         }
2922       }
2923       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2924     }
2925     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);
2926   }
2927   for (h = 0; h < height+1; ++h) {
2928     PetscInt dof;
2929 
2930     /* Copy in cone of first point */
2931     dof = offsets[h+1] - offsets[h];
2932     for (meetSize = 0; meetSize < dof; ++meetSize) {
2933       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2934     }
2935     /* Check each successive cone */
2936     for (p = 1; p < numPoints && meetSize; ++p) {
2937       PetscInt newMeetSize = 0;
2938 
2939       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2940       for (c = 0; c < dof; ++c) {
2941         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2942 
2943         for (m = 0; m < meetSize; ++m) {
2944           if (point == meet[i][m]) {
2945             meet[1-i][newMeetSize++] = point;
2946             break;
2947           }
2948         }
2949       }
2950       meetSize = newMeetSize;
2951       i        = 1-i;
2952     }
2953     if (meetSize) break;
2954   }
2955   *numCoveredPoints = meetSize;
2956   *coveredPoints    = meet[i];
2957   for (p = 0; p < numPoints; ++p) {
2958     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2959   }
2960   ierr = PetscFree(closures);CHKERRQ(ierr);
2961   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
2962   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
2963   PetscFunctionReturn(0);
2964 }
2965 
2966 /*@C
2967   DMPlexEqual - Determine if two DMs have the same topology
2968 
2969   Not Collective
2970 
2971   Input Parameters:
2972 + dmA - A DMPlex object
2973 - dmB - A DMPlex object
2974 
2975   Output Parameters:
2976 . equal - PETSC_TRUE if the topologies are identical
2977 
2978   Level: intermediate
2979 
2980   Notes:
2981   We are not solving graph isomorphism, so we do not permutation.
2982 
2983 .keywords: mesh
2984 .seealso: DMPlexGetCone()
2985 @*/
2986 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2987 {
2988   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
2989   PetscErrorCode ierr;
2990 
2991   PetscFunctionBegin;
2992   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
2993   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
2994   PetscValidPointer(equal, 3);
2995 
2996   *equal = PETSC_FALSE;
2997   ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr);
2998   ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr);
2999   if (depth != depthB) PetscFunctionReturn(0);
3000   ierr = DMPlexGetChart(dmA, &pStart,  &pEnd);CHKERRQ(ierr);
3001   ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr);
3002   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
3003   for (p = pStart; p < pEnd; ++p) {
3004     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3005     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
3006 
3007     ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr);
3008     ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr);
3009     ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr);
3010     ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr);
3011     ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr);
3012     ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr);
3013     if (coneSize != coneSizeB) PetscFunctionReturn(0);
3014     for (c = 0; c < coneSize; ++c) {
3015       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
3016       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
3017     }
3018     ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr);
3019     ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr);
3020     ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr);
3021     ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr);
3022     if (supportSize != supportSizeB) PetscFunctionReturn(0);
3023     for (s = 0; s < supportSize; ++s) {
3024       if (support[s] != supportB[s]) PetscFunctionReturn(0);
3025     }
3026   }
3027   *equal = PETSC_TRUE;
3028   PetscFunctionReturn(0);
3029 }
3030 
3031 /*@C
3032   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
3033 
3034   Not Collective
3035 
3036   Input Parameters:
3037 + dm         - The DMPlex
3038 . cellDim    - The cell dimension
3039 - numCorners - The number of vertices on a cell
3040 
3041   Output Parameters:
3042 . numFaceVertices - The number of vertices on a face
3043 
3044   Level: developer
3045 
3046   Notes:
3047   Of course this can only work for a restricted set of symmetric shapes
3048 
3049 .seealso: DMPlexGetCone()
3050 @*/
3051 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3052 {
3053   MPI_Comm       comm;
3054   PetscErrorCode ierr;
3055 
3056   PetscFunctionBegin;
3057   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3058   PetscValidPointer(numFaceVertices,3);
3059   switch (cellDim) {
3060   case 0:
3061     *numFaceVertices = 0;
3062     break;
3063   case 1:
3064     *numFaceVertices = 1;
3065     break;
3066   case 2:
3067     switch (numCorners) {
3068     case 3: /* triangle */
3069       *numFaceVertices = 2; /* Edge has 2 vertices */
3070       break;
3071     case 4: /* quadrilateral */
3072       *numFaceVertices = 2; /* Edge has 2 vertices */
3073       break;
3074     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3075       *numFaceVertices = 3; /* Edge has 3 vertices */
3076       break;
3077     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3078       *numFaceVertices = 3; /* Edge has 3 vertices */
3079       break;
3080     default:
3081       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3082     }
3083     break;
3084   case 3:
3085     switch (numCorners) {
3086     case 4: /* tetradehdron */
3087       *numFaceVertices = 3; /* Face has 3 vertices */
3088       break;
3089     case 6: /* tet cohesive cells */
3090       *numFaceVertices = 4; /* Face has 4 vertices */
3091       break;
3092     case 8: /* hexahedron */
3093       *numFaceVertices = 4; /* Face has 4 vertices */
3094       break;
3095     case 9: /* tet cohesive Lagrange cells */
3096       *numFaceVertices = 6; /* Face has 6 vertices */
3097       break;
3098     case 10: /* quadratic tetrahedron */
3099       *numFaceVertices = 6; /* Face has 6 vertices */
3100       break;
3101     case 12: /* hex cohesive Lagrange cells */
3102       *numFaceVertices = 6; /* Face has 6 vertices */
3103       break;
3104     case 18: /* quadratic tet cohesive Lagrange cells */
3105       *numFaceVertices = 6; /* Face has 6 vertices */
3106       break;
3107     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3108       *numFaceVertices = 9; /* Face has 9 vertices */
3109       break;
3110     default:
3111       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3112     }
3113     break;
3114   default:
3115     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3116   }
3117   PetscFunctionReturn(0);
3118 }
3119 
3120 /*@
3121   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
3122 
3123   Not Collective
3124 
3125   Input Parameter:
3126 . dm    - The DMPlex object
3127 
3128   Output Parameter:
3129 . depthLabel - The DMLabel recording point depth
3130 
3131   Level: developer
3132 
3133 .keywords: mesh, points
3134 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3135 @*/
3136 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3137 {
3138   PetscErrorCode ierr;
3139 
3140   PetscFunctionBegin;
3141   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3142   PetscValidPointer(depthLabel, 2);
3143   if (!dm->depthLabel) {ierr = DMGetLabel(dm, "depth", &dm->depthLabel);CHKERRQ(ierr);}
3144   *depthLabel = dm->depthLabel;
3145   PetscFunctionReturn(0);
3146 }
3147 
3148 /*@
3149   DMPlexGetDepth - Get the depth of the DAG representing this mesh
3150 
3151   Not Collective
3152 
3153   Input Parameter:
3154 . dm    - The DMPlex object
3155 
3156   Output Parameter:
3157 . depth - The number of strata (breadth first levels) in the DAG
3158 
3159   Level: developer
3160 
3161 .keywords: mesh, points
3162 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3163 @*/
3164 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3165 {
3166   DMLabel        label;
3167   PetscInt       d = 0;
3168   PetscErrorCode ierr;
3169 
3170   PetscFunctionBegin;
3171   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3172   PetscValidPointer(depth, 2);
3173   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3174   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
3175   *depth = d-1;
3176   PetscFunctionReturn(0);
3177 }
3178 
3179 /*@
3180   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
3181 
3182   Not Collective
3183 
3184   Input Parameters:
3185 + dm           - The DMPlex object
3186 - stratumValue - The requested depth
3187 
3188   Output Parameters:
3189 + start - The first point at this depth
3190 - end   - One beyond the last point at this depth
3191 
3192   Level: developer
3193 
3194 .keywords: mesh, points
3195 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3196 @*/
3197 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3198 {
3199   DMLabel        label;
3200   PetscInt       pStart, pEnd;
3201   PetscErrorCode ierr;
3202 
3203   PetscFunctionBegin;
3204   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3205   if (start) {PetscValidPointer(start, 3); *start = 0;}
3206   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
3207   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3208   if (pStart == pEnd) PetscFunctionReturn(0);
3209   if (stratumValue < 0) {
3210     if (start) *start = pStart;
3211     if (end)   *end   = pEnd;
3212     PetscFunctionReturn(0);
3213   }
3214   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3215   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3216   ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr);
3217   PetscFunctionReturn(0);
3218 }
3219 
3220 /*@
3221   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
3222 
3223   Not Collective
3224 
3225   Input Parameters:
3226 + dm           - The DMPlex object
3227 - stratumValue - The requested height
3228 
3229   Output Parameters:
3230 + start - The first point at this height
3231 - end   - One beyond the last point at this height
3232 
3233   Level: developer
3234 
3235 .keywords: mesh, points
3236 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3237 @*/
3238 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3239 {
3240   DMLabel        label;
3241   PetscInt       depth, pStart, pEnd;
3242   PetscErrorCode ierr;
3243 
3244   PetscFunctionBegin;
3245   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3246   if (start) {PetscValidPointer(start, 3); *start = 0;}
3247   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
3248   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3249   if (pStart == pEnd) PetscFunctionReturn(0);
3250   if (stratumValue < 0) {
3251     if (start) *start = pStart;
3252     if (end)   *end   = pEnd;
3253     PetscFunctionReturn(0);
3254   }
3255   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3256   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3257   ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr);
3258   ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr);
3259   PetscFunctionReturn(0);
3260 }
3261 
3262 /* Set the number of dof on each point and separate by fields */
3263 static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3264 {
3265   PetscInt      *pMax;
3266   PetscInt       depth, cellHeight, pStart = 0, pEnd = 0;
3267   PetscInt       Nf, p, d, dep, f;
3268   PetscBool     *isFE;
3269   PetscErrorCode ierr;
3270 
3271   PetscFunctionBegin;
3272   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
3273   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
3274   for (f = 0; f < numFields; ++f) {
3275     PetscObject  obj;
3276     PetscClassId id;
3277 
3278     isFE[f] = PETSC_FALSE;
3279     if (f >= Nf) continue;
3280     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
3281     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
3282     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
3283     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3284   }
3285   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
3286   if (numFields > 0) {
3287     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
3288     if (numComp) {
3289       for (f = 0; f < numFields; ++f) {
3290         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
3291         if (isFE[f]) {
3292           PetscFE           fe;
3293           PetscDualSpace    dspace;
3294           const PetscInt    ***perms;
3295           const PetscScalar ***flips;
3296           const PetscInt    *numDof;
3297 
3298           ierr = DMGetField(dm,f,(PetscObject *) &fe);CHKERRQ(ierr);
3299           ierr = PetscFEGetDualSpace(fe,&dspace);CHKERRQ(ierr);
3300           ierr = PetscDualSpaceGetSymmetries(dspace,&perms,&flips);CHKERRQ(ierr);
3301           ierr = PetscDualSpaceGetNumDof(dspace,&numDof);CHKERRQ(ierr);
3302           if (perms || flips) {
3303             DM               K;
3304             DMLabel          depthLabel;
3305             PetscInt         depth, h;
3306             PetscSectionSym  sym;
3307 
3308             ierr = PetscDualSpaceGetDM(dspace,&K);CHKERRQ(ierr);
3309             ierr = DMPlexGetDepthLabel(dm,&depthLabel);CHKERRQ(ierr);
3310             ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr);
3311             ierr = PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);CHKERRQ(ierr);
3312             for (h = 0; h <= depth; h++) {
3313               PetscDualSpace    hspace;
3314               PetscInt          kStart, kEnd;
3315               PetscInt          kConeSize;
3316               const PetscInt    **perms0 = NULL;
3317               const PetscScalar **flips0 = NULL;
3318 
3319               ierr = PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);CHKERRQ(ierr);
3320               ierr = DMPlexGetHeightStratum(K,h,&kStart,&kEnd);CHKERRQ(ierr);
3321               if (!hspace) continue;
3322               ierr = PetscDualSpaceGetSymmetries(hspace,&perms,&flips);CHKERRQ(ierr);
3323               if (perms) perms0 = perms[0];
3324               if (flips) flips0 = flips[0];
3325               if (!(perms0 || flips0)) continue;
3326               ierr = DMPlexGetConeSize(K,kStart,&kConeSize);CHKERRQ(ierr);
3327               ierr = PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);CHKERRQ(ierr);
3328             }
3329             ierr = PetscSectionSetFieldSym(*section,f,sym);CHKERRQ(ierr);
3330             ierr = PetscSectionSymDestroy(&sym);CHKERRQ(ierr);
3331           }
3332         }
3333       }
3334     }
3335   }
3336   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3337   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
3338   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3339   ierr = PetscMalloc1(depth+1,&pMax);CHKERRQ(ierr);
3340   ierr = DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);CHKERRQ(ierr);
3341   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
3342   for (dep = 0; dep <= depth - cellHeight; ++dep) {
3343     d    = dim == depth ? dep : (!dep ? 0 : dim);
3344     ierr = DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);CHKERRQ(ierr);
3345     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3346     for (p = pStart; p < pEnd; ++p) {
3347       PetscInt tot = 0;
3348 
3349       for (f = 0; f < numFields; ++f) {
3350         if (isFE[f] && p >= pMax[dep]) continue;
3351         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
3352         tot += numDof[f*(dim+1)+d];
3353       }
3354       ierr = PetscSectionSetDof(*section, p, tot);CHKERRQ(ierr);
3355     }
3356   }
3357   ierr = PetscFree(pMax);CHKERRQ(ierr);
3358   ierr = PetscFree(isFE);CHKERRQ(ierr);
3359   PetscFunctionReturn(0);
3360 }
3361 
3362 /* Set the number of dof on each point and separate by fields
3363    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3364 */
3365 static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3366 {
3367   PetscInt       numFields;
3368   PetscInt       bc;
3369   PetscSection   aSec;
3370   PetscErrorCode ierr;
3371 
3372   PetscFunctionBegin;
3373   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3374   for (bc = 0; bc < numBC; ++bc) {
3375     PetscInt        field = 0;
3376     const PetscInt *comp;
3377     const PetscInt *idx;
3378     PetscInt        Nc = -1, n, i;
3379 
3380     if (numFields) field = bcField[bc];
3381     if (bcComps && bcComps[bc]) {ierr = ISGetLocalSize(bcComps[bc], &Nc);CHKERRQ(ierr);}
3382     if (bcComps && bcComps[bc]) {ierr = ISGetIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3383     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
3384     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3385     for (i = 0; i < n; ++i) {
3386       const PetscInt p = idx[i];
3387       PetscInt       numConst;
3388 
3389       if (numFields) {
3390         ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
3391       } else {
3392         ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
3393       }
3394       /* If Nc < 0, constrain every dof on the point */
3395       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3396       if (numFields) {ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);}
3397       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
3398     }
3399     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3400     if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3401   }
3402   ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr);
3403   if (aSec) {
3404     PetscInt aStart, aEnd, a;
3405 
3406     ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr);
3407     for (a = aStart; a < aEnd; a++) {
3408       PetscInt dof, f;
3409 
3410       ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr);
3411       if (dof) {
3412         /* if there are point-to-point constraints, then all dofs are constrained */
3413         ierr = PetscSectionGetDof(section, a, &dof);CHKERRQ(ierr);
3414         ierr = PetscSectionSetConstraintDof(section, a, dof);CHKERRQ(ierr);
3415         for (f = 0; f < numFields; f++) {
3416           ierr = PetscSectionGetFieldDof(section, a, f, &dof);CHKERRQ(ierr);
3417           ierr = PetscSectionSetFieldConstraintDof(section, a, f, dof);CHKERRQ(ierr);
3418         }
3419       }
3420     }
3421   }
3422   PetscFunctionReturn(0);
3423 }
3424 
3425 /* Set the constrained field indices on each point
3426    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3427 */
3428 static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3429 {
3430   PetscSection   aSec;
3431   PetscInt      *indices;
3432   PetscInt       numFields, cdof, maxDof = 0, pStart, pEnd, p, bc, f, d;
3433   PetscErrorCode ierr;
3434 
3435   PetscFunctionBegin;
3436   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3437   if (!numFields) PetscFunctionReturn(0);
3438   /* Initialize all field indices to -1 */
3439   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3440   for (p = pStart; p < pEnd; ++p) {ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); maxDof = PetscMax(maxDof, cdof);}
3441   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
3442   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3443   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {ierr = PetscSectionSetFieldConstraintIndices(section, p, f, indices);CHKERRQ(ierr);}
3444   /* Handle BC constraints */
3445   for (bc = 0; bc < numBC; ++bc) {
3446     const PetscInt  field = bcField[bc];
3447     const PetscInt *comp, *idx;
3448     PetscInt        Nc = -1, n, i;
3449 
3450     if (bcComps && bcComps[bc]) {ierr = ISGetLocalSize(bcComps[bc], &Nc);CHKERRQ(ierr);}
3451     if (bcComps && bcComps[bc]) {ierr = ISGetIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3452     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
3453     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3454     for (i = 0; i < n; ++i) {
3455       const PetscInt  p = idx[i];
3456       const PetscInt *find;
3457       PetscInt        fdof, fcdof, c;
3458 
3459       ierr = PetscSectionGetFieldDof(section, p, field, &fdof);CHKERRQ(ierr);
3460       if (!fdof) continue;
3461       if (Nc < 0) {
3462         for (d = 0; d < fdof; ++d) indices[d] = d;
3463         fcdof = fdof;
3464       } else {
3465         ierr = PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);CHKERRQ(ierr);
3466         ierr = PetscSectionGetFieldConstraintIndices(section, p, field, &find);CHKERRQ(ierr);
3467         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3468         for (c = 0; c < Nc; ++c) indices[d++] = comp[c];
3469         ierr = PetscSortRemoveDupsInt(&d, indices);CHKERRQ(ierr);
3470         for (c = d; c < fcdof; ++c) indices[c] = -1;
3471         fcdof = d;
3472       }
3473       ierr = PetscSectionSetFieldConstraintDof(section, p, field, fcdof);CHKERRQ(ierr);
3474       ierr = PetscSectionSetFieldConstraintIndices(section, p, field, indices);CHKERRQ(ierr);
3475     }
3476     if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3477     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3478   }
3479   /* Handle anchors */
3480   ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr);
3481   if (aSec) {
3482     PetscInt aStart, aEnd, a;
3483 
3484     for (d = 0; d < maxDof; ++d) indices[d] = d;
3485     ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr);
3486     for (a = aStart; a < aEnd; a++) {
3487       PetscInt dof, f;
3488 
3489       ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr);
3490       if (dof) {
3491         /* if there are point-to-point constraints, then all dofs are constrained */
3492         for (f = 0; f < numFields; f++) {
3493           ierr = PetscSectionSetFieldConstraintIndices(section, a, f, indices);CHKERRQ(ierr);
3494         }
3495       }
3496     }
3497   }
3498   ierr = PetscFree(indices);CHKERRQ(ierr);
3499   PetscFunctionReturn(0);
3500 }
3501 
3502 /* Set the constrained indices on each point */
3503 static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3504 {
3505   PetscInt      *indices;
3506   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;
3507   PetscErrorCode ierr;
3508 
3509   PetscFunctionBegin;
3510   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3511   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
3512   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3513   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
3514   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3515   for (p = pStart; p < pEnd; ++p) {
3516     PetscInt cdof, d;
3517 
3518     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
3519     if (cdof) {
3520       if (numFields) {
3521         PetscInt numConst = 0, foff = 0;
3522 
3523         for (f = 0; f < numFields; ++f) {
3524           const PetscInt *find;
3525           PetscInt        fcdof, fdof;
3526 
3527           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
3528           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
3529           /* Change constraint numbering from field component to local dof number */
3530           ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &find);CHKERRQ(ierr);
3531           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3532           numConst += fcdof;
3533           foff     += fdof;
3534         }
3535         if (cdof != numConst) {ierr = PetscSectionSetConstraintDof(section, p, numConst);CHKERRQ(ierr);}
3536       } else {
3537         for (d = 0; d < cdof; ++d) indices[d] = d;
3538       }
3539       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
3540     }
3541   }
3542   ierr = PetscFree(indices);CHKERRQ(ierr);
3543   PetscFunctionReturn(0);
3544 }
3545 
3546 /*@C
3547   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
3548 
3549   Not Collective
3550 
3551   Input Parameters:
3552 + dm        - The DMPlex object
3553 . dim       - The spatial dimension of the problem
3554 . numFields - The number of fields in the problem
3555 . numComp   - An array of size numFields that holds the number of components for each field
3556 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3557 . numBC     - The number of boundary conditions
3558 . bcField   - An array of size numBC giving the field number for each boundry condition
3559 . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3560 . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3561 - perm      - Optional permutation of the chart, or NULL
3562 
3563   Output Parameter:
3564 . section - The PetscSection object
3565 
3566   Notes:
3567     numDof[f*(dim+1)+d] gives the number of dof for field f on points of dimension d. For instance, numDof[1] is the
3568   number of dof for field 0 on each edge.
3569 
3570   The chart permutation is the same one set using PetscSectionSetPermutation()
3571 
3572   Level: developer
3573 
3574   Fortran Notes:
3575   A Fortran 90 version is available as DMPlexCreateSectionF90()
3576 
3577 .keywords: mesh, elements
3578 .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3579 @*/
3580 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], IS perm, PetscSection *section)
3581 {
3582   PetscSection   aSec;
3583   PetscErrorCode ierr;
3584 
3585   PetscFunctionBegin;
3586   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
3587   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
3588   if (perm) {ierr = PetscSectionSetPermutation(*section, perm);CHKERRQ(ierr);}
3589   ierr = PetscSectionSetFromOptions(*section);CHKERRQ(ierr);
3590   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3591   ierr = DMPlexGetAnchors(dm,&aSec,NULL);CHKERRQ(ierr);
3592   if (numBC || aSec) {
3593     ierr = DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
3594     ierr = DMPlexCreateSectionBCIndices(dm, *section);CHKERRQ(ierr);
3595   }
3596   ierr = PetscSectionViewFromOptions(*section,NULL,"-section_view");CHKERRQ(ierr);
3597   PetscFunctionReturn(0);
3598 }
3599 
3600 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3601 {
3602   PetscSection   section, s;
3603   Mat            m;
3604   PetscInt       maxHeight;
3605   PetscErrorCode ierr;
3606 
3607   PetscFunctionBegin;
3608   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
3609   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
3610   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr);
3611   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
3612   ierr = DMSetSection(*cdm, section);CHKERRQ(ierr);
3613   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
3614   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
3615   ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr);
3616   ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr);
3617   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
3618   ierr = MatDestroy(&m);CHKERRQ(ierr);
3619   PetscFunctionReturn(0);
3620 }
3621 
3622 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3623 {
3624   Vec            coordsLocal;
3625   DM             coordsDM;
3626   PetscErrorCode ierr;
3627 
3628   PetscFunctionBegin;
3629   *field = NULL;
3630   ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr);
3631   ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr);
3632   if (coordsLocal && coordsDM) {
3633     ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr);
3634   }
3635   PetscFunctionReturn(0);
3636 }
3637 
3638 /*@C
3639   DMPlexGetConeSection - Return a section which describes the layout of cone data
3640 
3641   Not Collective
3642 
3643   Input Parameters:
3644 . dm        - The DMPlex object
3645 
3646   Output Parameter:
3647 . section - The PetscSection object
3648 
3649   Level: developer
3650 
3651 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3652 @*/
3653 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3654 {
3655   DM_Plex *mesh = (DM_Plex*) dm->data;
3656 
3657   PetscFunctionBegin;
3658   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3659   if (section) *section = mesh->coneSection;
3660   PetscFunctionReturn(0);
3661 }
3662 
3663 /*@C
3664   DMPlexGetSupportSection - Return a section which describes the layout of support data
3665 
3666   Not Collective
3667 
3668   Input Parameters:
3669 . dm        - The DMPlex object
3670 
3671   Output Parameter:
3672 . section - The PetscSection object
3673 
3674   Level: developer
3675 
3676 .seealso: DMPlexGetConeSection()
3677 @*/
3678 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3679 {
3680   DM_Plex *mesh = (DM_Plex*) dm->data;
3681 
3682   PetscFunctionBegin;
3683   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3684   if (section) *section = mesh->supportSection;
3685   PetscFunctionReturn(0);
3686 }
3687 
3688 /*@C
3689   DMPlexGetCones - Return cone data
3690 
3691   Not Collective
3692 
3693   Input Parameters:
3694 . dm        - The DMPlex object
3695 
3696   Output Parameter:
3697 . cones - The cone for each point
3698 
3699   Level: developer
3700 
3701 .seealso: DMPlexGetConeSection()
3702 @*/
3703 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3704 {
3705   DM_Plex *mesh = (DM_Plex*) dm->data;
3706 
3707   PetscFunctionBegin;
3708   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3709   if (cones) *cones = mesh->cones;
3710   PetscFunctionReturn(0);
3711 }
3712 
3713 /*@C
3714   DMPlexGetConeOrientations - Return cone orientation data
3715 
3716   Not Collective
3717 
3718   Input Parameters:
3719 . dm        - The DMPlex object
3720 
3721   Output Parameter:
3722 . coneOrientations - The cone orientation for each point
3723 
3724   Level: developer
3725 
3726 .seealso: DMPlexGetConeSection()
3727 @*/
3728 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3729 {
3730   DM_Plex *mesh = (DM_Plex*) dm->data;
3731 
3732   PetscFunctionBegin;
3733   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3734   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3735   PetscFunctionReturn(0);
3736 }
3737 
3738 /******************************** FEM Support **********************************/
3739 
3740 PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3741 {
3742   DMLabel        label;
3743   PetscInt      *perm;
3744   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3745   PetscErrorCode ierr;
3746 
3747   PetscFunctionBegin;
3748   if (point < 0) {ierr = DMPlexGetDepthStratum(dm, 1, &point, NULL);CHKERRQ(ierr);}
3749   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3750   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3751   ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr);
3752   if (depth == 1) {eStart = point;}
3753   else if  (depth == dim) {
3754     const PetscInt *cone;
3755 
3756     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3757     eStart = cone[0];
3758   } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering", point, depth);
3759   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
3760   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
3761   if (dim <= 1) PetscFunctionReturn(0);
3762   for (f = 0; f < Nf; ++f) {
3763     /* An order k SEM disc has k-1 dofs on an edge */
3764     ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3765     ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3766     k = k/Nc + 1;
3767     size += PetscPowInt(k+1, dim)*Nc;
3768   }
3769   ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
3770   for (f = 0; f < Nf; ++f) {
3771     switch (dim) {
3772     case 2:
3773       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3774       ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3775       ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3776       k = k/Nc + 1;
3777       /* The SEM order is
3778 
3779          v_lb, {e_b}, v_rb,
3780          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3781          v_lt, reverse {e_t}, v_rt
3782       */
3783       {
3784         const PetscInt of   = 0;
3785         const PetscInt oeb  = of   + PetscSqr(k-1);
3786         const PetscInt oer  = oeb  + (k-1);
3787         const PetscInt oet  = oer  + (k-1);
3788         const PetscInt oel  = oet  + (k-1);
3789         const PetscInt ovlb = oel  + (k-1);
3790         const PetscInt ovrb = ovlb + 1;
3791         const PetscInt ovrt = ovrb + 1;
3792         const PetscInt ovlt = ovrt + 1;
3793         PetscInt       o;
3794 
3795         /* bottom */
3796         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3797         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3798         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3799         /* middle */
3800         for (i = 0; i < k-1; ++i) {
3801           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3802           for (o = of+(k-1)*i; o < of+(k-1)*(i+1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3803           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3804         }
3805         /* top */
3806         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3807         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3808         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3809         foffset = offset;
3810       }
3811       break;
3812     case 3:
3813       /* The original hex closure is
3814 
3815          {c,
3816           f_b, f_t, f_f, f_b, f_r, f_l,
3817           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3818           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3819       */
3820       ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3821       ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3822       k = k/Nc + 1;
3823       /* The SEM order is
3824          Bottom Slice
3825          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3826          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3827          v_blb, {e_bb}, v_brb,
3828 
3829          Middle Slice (j)
3830          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3831          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3832          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
3833 
3834          Top Slice
3835          v_tlf, {e_tf}, v_trf,
3836          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3837          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3838       */
3839       {
3840         const PetscInt oc    = 0;
3841         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3842         const PetscInt oft   = ofb   + PetscSqr(k-1);
3843         const PetscInt off   = oft   + PetscSqr(k-1);
3844         const PetscInt ofk   = off   + PetscSqr(k-1);
3845         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3846         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3847         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3848         const PetscInt oebb  = oebl  + (k-1);
3849         const PetscInt oebr  = oebb  + (k-1);
3850         const PetscInt oebf  = oebr  + (k-1);
3851         const PetscInt oetf  = oebf  + (k-1);
3852         const PetscInt oetr  = oetf  + (k-1);
3853         const PetscInt oetb  = oetr  + (k-1);
3854         const PetscInt oetl  = oetb  + (k-1);
3855         const PetscInt oerf  = oetl  + (k-1);
3856         const PetscInt oelf  = oerf  + (k-1);
3857         const PetscInt oelb  = oelf  + (k-1);
3858         const PetscInt oerb  = oelb  + (k-1);
3859         const PetscInt ovblf = oerb  + (k-1);
3860         const PetscInt ovblb = ovblf + 1;
3861         const PetscInt ovbrb = ovblb + 1;
3862         const PetscInt ovbrf = ovbrb + 1;
3863         const PetscInt ovtlf = ovbrf + 1;
3864         const PetscInt ovtrf = ovtlf + 1;
3865         const PetscInt ovtrb = ovtrf + 1;
3866         const PetscInt ovtlb = ovtrb + 1;
3867         PetscInt       o, n;
3868 
3869         /* Bottom Slice */
3870         /*   bottom */
3871         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3872         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3873         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3874         /*   middle */
3875         for (i = 0; i < k-1; ++i) {
3876           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3877           for (n = 0; n < k-1; ++n) {o = ofb+n*(k-1)+i; for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;}
3878           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3879         }
3880         /*   top */
3881         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3882         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3883         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
3884 
3885         /* Middle Slice */
3886         for (j = 0; j < k-1; ++j) {
3887           /*   bottom */
3888           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3889           for (o = off+j*(k-1); o < off+(j+1)*(k-1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3890           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3891           /*   middle */
3892           for (i = 0; i < k-1; ++i) {
3893             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3894             for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc+(j*(k-1)+i)*(k-1)+n)*Nc + c + foffset;
3895             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3896           }
3897           /*   top */
3898           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3899           for (o = ofk+j*(k-1)+(k-2); o >= ofk+j*(k-1); --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3900           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3901         }
3902 
3903         /* Top Slice */
3904         /*   bottom */
3905         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3906         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3907         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3908         /*   middle */
3909         for (i = 0; i < k-1; ++i) {
3910           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3911           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3912           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3913         }
3914         /*   top */
3915         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3916         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3917         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
3918 
3919         foffset = offset;
3920       }
3921       break;
3922     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3923     }
3924   }
3925   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3926   /* Check permutation */
3927   {
3928     PetscInt *check;
3929 
3930     ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
3931     for (i = 0; i < size; ++i) {check[i] = -1; if (perm[i] < 0 || perm[i] >= size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%D] = %D", i, perm[i]);}
3932     for (i = 0; i < size; ++i) check[perm[i]] = i;
3933     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3934     ierr = PetscFree(check);CHKERRQ(ierr);
3935   }
3936   ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
3937   PetscFunctionReturn(0);
3938 }
3939 
3940 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3941 {
3942   PetscDS        prob;
3943   PetscInt       depth, Nf, h;
3944   DMLabel        label;
3945   PetscErrorCode ierr;
3946 
3947   PetscFunctionBeginHot;
3948   prob    = dm->prob;
3949   Nf      = prob->Nf;
3950   label   = dm->depthLabel;
3951   *dspace = NULL;
3952   if (field < Nf) {
3953     PetscObject disc = prob->disc[field];
3954 
3955     if (disc->classid == PETSCFE_CLASSID) {
3956       PetscDualSpace dsp;
3957 
3958       ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
3959       ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr);
3960       ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr);
3961       h    = depth - 1 - h;
3962       if (h) {
3963         ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr);
3964       } else {
3965         *dspace = dsp;
3966       }
3967     }
3968   }
3969   PetscFunctionReturn(0);
3970 }
3971 
3972 
3973 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3974 {
3975   PetscScalar    *array, *vArray;
3976   const PetscInt *cone, *coneO;
3977   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3978   PetscErrorCode  ierr;
3979 
3980   PetscFunctionBeginHot;
3981   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3982   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
3983   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3984   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
3985   if (!values || !*values) {
3986     if ((point >= pStart) && (point < pEnd)) {
3987       PetscInt dof;
3988 
3989       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3990       size += dof;
3991     }
3992     for (p = 0; p < numPoints; ++p) {
3993       const PetscInt cp = cone[p];
3994       PetscInt       dof;
3995 
3996       if ((cp < pStart) || (cp >= pEnd)) continue;
3997       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3998       size += dof;
3999     }
4000     if (!values) {
4001       if (csize) *csize = size;
4002       PetscFunctionReturn(0);
4003     }
4004     ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr);
4005   } else {
4006     array = *values;
4007   }
4008   size = 0;
4009   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4010   if ((point >= pStart) && (point < pEnd)) {
4011     PetscInt     dof, off, d;
4012     PetscScalar *varr;
4013 
4014     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4015     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4016     varr = &vArray[off];
4017     for (d = 0; d < dof; ++d, ++offset) {
4018       array[offset] = varr[d];
4019     }
4020     size += dof;
4021   }
4022   for (p = 0; p < numPoints; ++p) {
4023     const PetscInt cp = cone[p];
4024     PetscInt       o  = coneO[p];
4025     PetscInt       dof, off, d;
4026     PetscScalar   *varr;
4027 
4028     if ((cp < pStart) || (cp >= pEnd)) continue;
4029     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4030     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
4031     varr = &vArray[off];
4032     if (o >= 0) {
4033       for (d = 0; d < dof; ++d, ++offset) {
4034         array[offset] = varr[d];
4035       }
4036     } else {
4037       for (d = dof-1; d >= 0; --d, ++offset) {
4038         array[offset] = varr[d];
4039       }
4040     }
4041     size += dof;
4042   }
4043   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4044   if (!*values) {
4045     if (csize) *csize = size;
4046     *values = array;
4047   } else {
4048     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4049     *csize = size;
4050   }
4051   PetscFunctionReturn(0);
4052 }
4053 
4054 static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4055 {
4056   const PetscInt *cla;
4057   PetscInt       np, *pts = NULL;
4058   PetscErrorCode ierr;
4059 
4060   PetscFunctionBeginHot;
4061   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
4062   if (!*clPoints) {
4063     PetscInt pStart, pEnd, p, q;
4064 
4065     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4066     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
4067     /* Compress out points not in the section */
4068     for (p = 0, q = 0; p < np; p++) {
4069       PetscInt r = pts[2*p];
4070       if ((r >= pStart) && (r < pEnd)) {
4071         pts[q*2]   = r;
4072         pts[q*2+1] = pts[2*p+1];
4073         ++q;
4074       }
4075     }
4076     np = q;
4077     cla = NULL;
4078   } else {
4079     PetscInt dof, off;
4080 
4081     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
4082     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
4083     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
4084     np   = dof/2;
4085     pts  = (PetscInt *) &cla[off];
4086   }
4087   *numPoints = np;
4088   *points    = pts;
4089   *clp       = cla;
4090 
4091   PetscFunctionReturn(0);
4092 }
4093 
4094 static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4095 {
4096   PetscErrorCode ierr;
4097 
4098   PetscFunctionBeginHot;
4099   if (!*clPoints) {
4100     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
4101   } else {
4102     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
4103   }
4104   *numPoints = 0;
4105   *points    = NULL;
4106   *clSec     = NULL;
4107   *clPoints  = NULL;
4108   *clp       = NULL;
4109   PetscFunctionReturn(0);
4110 }
4111 
4112 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
4113 {
4114   PetscInt          offset = 0, p;
4115   const PetscInt    **perms = NULL;
4116   const PetscScalar **flips = NULL;
4117   PetscErrorCode    ierr;
4118 
4119   PetscFunctionBeginHot;
4120   *size = 0;
4121   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4122   for (p = 0; p < numPoints; p++) {
4123     const PetscInt    point = points[2*p];
4124     const PetscInt    *perm = perms ? perms[p] : NULL;
4125     const PetscScalar *flip = flips ? flips[p] : NULL;
4126     PetscInt          dof, off, d;
4127     const PetscScalar *varr;
4128 
4129     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4130     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4131     varr = &vArray[off];
4132     if (clperm) {
4133       if (perm) {
4134         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4135       } else {
4136         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4137       }
4138       if (flip) {
4139         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4140       }
4141     } else {
4142       if (perm) {
4143         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4144       } else {
4145         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4146       }
4147       if (flip) {
4148         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4149       }
4150     }
4151     offset += dof;
4152   }
4153   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4154   *size = offset;
4155   PetscFunctionReturn(0);
4156 }
4157 
4158 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
4159 {
4160   PetscInt          offset = 0, f;
4161   PetscErrorCode    ierr;
4162 
4163   PetscFunctionBeginHot;
4164   *size = 0;
4165   for (f = 0; f < numFields; ++f) {
4166     PetscInt          p;
4167     const PetscInt    **perms = NULL;
4168     const PetscScalar **flips = NULL;
4169 
4170     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4171     for (p = 0; p < numPoints; p++) {
4172       const PetscInt    point = points[2*p];
4173       PetscInt          fdof, foff, b;
4174       const PetscScalar *varr;
4175       const PetscInt    *perm = perms ? perms[p] : NULL;
4176       const PetscScalar *flip = flips ? flips[p] : NULL;
4177 
4178       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4179       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4180       varr = &vArray[foff];
4181       if (clperm) {
4182         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4183         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4184         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4185       } else {
4186         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4187         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4188         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4189       }
4190       offset += fdof;
4191     }
4192     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4193   }
4194   *size = offset;
4195   PetscFunctionReturn(0);
4196 }
4197 
4198 /*@C
4199   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4200 
4201   Not collective
4202 
4203   Input Parameters:
4204 + dm - The DM
4205 . section - The section describing the layout in v, or NULL to use the default section
4206 . v - The local vector
4207 . point - The point in the DM
4208 . csize - The size of the input values array, or NULL
4209 - values - An array to use for the values, or NULL to have it allocated automatically
4210 
4211   Output Parameters:
4212 + csize - The number of values in the closure
4213 - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4214 
4215 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4216 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4217 $ assembly function, and a user may already have allocated storage for this operation.
4218 $
4219 $ A typical use could be
4220 $
4221 $  values = NULL;
4222 $  ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4223 $  for (cl = 0; cl < clSize; ++cl) {
4224 $    <Compute on closure>
4225 $  }
4226 $  ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4227 $
4228 $ or
4229 $
4230 $  PetscMalloc1(clMaxSize, &values);
4231 $  for (p = pStart; p < pEnd; ++p) {
4232 $    clSize = clMaxSize;
4233 $    ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4234 $    for (cl = 0; cl < clSize; ++cl) {
4235 $      <Compute on closure>
4236 $    }
4237 $  }
4238 $  PetscFree(values);
4239 
4240   Fortran Notes:
4241   Since it returns an array, this routine is only available in Fortran 90, and you must
4242   include petsc.h90 in your code.
4243 
4244   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4245 
4246   Level: intermediate
4247 
4248 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4249 @*/
4250 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4251 {
4252   PetscSection       clSection;
4253   IS                 clPoints;
4254   PetscScalar       *array;
4255   const PetscScalar *vArray;
4256   PetscInt          *points = NULL;
4257   const PetscInt    *clp, *perm;
4258   PetscInt           depth, numFields, numPoints, size;
4259   PetscErrorCode     ierr;
4260 
4261   PetscFunctionBeginHot;
4262   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4263   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
4264   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4265   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4266   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4267   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4268   if (depth == 1 && numFields < 2) {
4269     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
4270     PetscFunctionReturn(0);
4271   }
4272   /* Get points */
4273   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4274   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr);
4275   /* Get array */
4276   if (!values || !*values) {
4277     PetscInt asize = 0, dof, p;
4278 
4279     for (p = 0; p < numPoints*2; p += 2) {
4280       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4281       asize += dof;
4282     }
4283     if (!values) {
4284       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4285       if (csize) *csize = asize;
4286       PetscFunctionReturn(0);
4287     }
4288     ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr);
4289   } else {
4290     array = *values;
4291   }
4292   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
4293   /* Get values */
4294   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
4295   else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);CHKERRQ(ierr);}
4296   /* Cleanup points */
4297   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4298   /* Cleanup array */
4299   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
4300   if (!*values) {
4301     if (csize) *csize = size;
4302     *values = array;
4303   } else {
4304     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4305     *csize = size;
4306   }
4307   PetscFunctionReturn(0);
4308 }
4309 
4310 /*@C
4311   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4312 
4313   Not collective
4314 
4315   Input Parameters:
4316 + dm - The DM
4317 . section - The section describing the layout in v, or NULL to use the default section
4318 . v - The local vector
4319 . point - The point in the DM
4320 . csize - The number of values in the closure, or NULL
4321 - values - The array of values, which is a borrowed array and should not be freed
4322 
4323   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
4324 
4325   Fortran Notes:
4326   Since it returns an array, this routine is only available in Fortran 90, and you must
4327   include petsc.h90 in your code.
4328 
4329   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4330 
4331   Level: intermediate
4332 
4333 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4334 @*/
4335 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4336 {
4337   PetscInt       size = 0;
4338   PetscErrorCode ierr;
4339 
4340   PetscFunctionBegin;
4341   /* Should work without recalculating size */
4342   ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr);
4343   *values = NULL;
4344   PetscFunctionReturn(0);
4345 }
4346 
4347 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
4348 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
4349 
4350 PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
4351 {
4352   PetscInt        cdof;   /* The number of constraints on this point */
4353   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4354   PetscScalar    *a;
4355   PetscInt        off, cind = 0, k;
4356   PetscErrorCode  ierr;
4357 
4358   PetscFunctionBegin;
4359   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4360   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4361   a    = &array[off];
4362   if (!cdof || setBC) {
4363     if (clperm) {
4364       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4365       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4366     } else {
4367       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4368       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4369     }
4370   } else {
4371     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4372     if (clperm) {
4373       if (perm) {for (k = 0; k < dof; ++k) {
4374           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4375           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4376         }
4377       } else {
4378         for (k = 0; k < dof; ++k) {
4379           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4380           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4381         }
4382       }
4383     } else {
4384       if (perm) {
4385         for (k = 0; k < dof; ++k) {
4386           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4387           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4388         }
4389       } else {
4390         for (k = 0; k < dof; ++k) {
4391           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4392           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4393         }
4394       }
4395     }
4396   }
4397   PetscFunctionReturn(0);
4398 }
4399 
4400 PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
4401 {
4402   PetscInt        cdof;   /* The number of constraints on this point */
4403   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4404   PetscScalar    *a;
4405   PetscInt        off, cind = 0, k;
4406   PetscErrorCode  ierr;
4407 
4408   PetscFunctionBegin;
4409   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4410   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4411   a    = &array[off];
4412   if (cdof) {
4413     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4414     if (clperm) {
4415       if (perm) {
4416         for (k = 0; k < dof; ++k) {
4417           if ((cind < cdof) && (k == cdofs[cind])) {
4418             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4419             cind++;
4420           }
4421         }
4422       } else {
4423         for (k = 0; k < dof; ++k) {
4424           if ((cind < cdof) && (k == cdofs[cind])) {
4425             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4426             cind++;
4427           }
4428         }
4429       }
4430     } else {
4431       if (perm) {
4432         for (k = 0; k < dof; ++k) {
4433           if ((cind < cdof) && (k == cdofs[cind])) {
4434             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4435             cind++;
4436           }
4437         }
4438       } else {
4439         for (k = 0; k < dof; ++k) {
4440           if ((cind < cdof) && (k == cdofs[cind])) {
4441             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4442             cind++;
4443           }
4444         }
4445       }
4446     }
4447   }
4448   PetscFunctionReturn(0);
4449 }
4450 
4451 PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, const PetscInt *perm, const PetscScalar *flip, PetscInt f, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4452 {
4453   PetscScalar    *a;
4454   PetscInt        fdof, foff, fcdof, foffset = *offset;
4455   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4456   PetscInt        cind = 0, b;
4457   PetscErrorCode  ierr;
4458 
4459   PetscFunctionBegin;
4460   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4461   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4462   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4463   a    = &array[foff];
4464   if (!fcdof || setBC) {
4465     if (clperm) {
4466       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4467       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4468     } else {
4469       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4470       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4471     }
4472   } else {
4473     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4474     if (clperm) {
4475       if (perm) {
4476         for (b = 0; b < fdof; b++) {
4477           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4478           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4479         }
4480       } else {
4481         for (b = 0; b < fdof; b++) {
4482           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4483           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4484         }
4485       }
4486     } else {
4487       if (perm) {
4488         for (b = 0; b < fdof; b++) {
4489           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4490           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4491         }
4492       } else {
4493         for (b = 0; b < fdof; b++) {
4494           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4495           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4496         }
4497       }
4498     }
4499   }
4500   *offset += fdof;
4501   PetscFunctionReturn(0);
4502 }
4503 
4504 PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4505 {
4506   PetscScalar    *a;
4507   PetscInt        fdof, foff, fcdof, foffset = *offset;
4508   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4509   PetscInt        cind = 0, ncind = 0, b;
4510   PetscBool       ncSet, fcSet;
4511   PetscErrorCode  ierr;
4512 
4513   PetscFunctionBegin;
4514   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4515   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4516   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4517   a    = &array[foff];
4518   if (fcdof) {
4519     /* We just override fcdof and fcdofs with Ncc and comps */
4520     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4521     if (clperm) {
4522       if (perm) {
4523         if (comps) {
4524           for (b = 0; b < fdof; b++) {
4525             ncSet = fcSet = PETSC_FALSE;
4526             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4527             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4528             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4529           }
4530         } else {
4531           for (b = 0; b < fdof; b++) {
4532             if ((cind < fcdof) && (b == fcdofs[cind])) {
4533               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4534               ++cind;
4535             }
4536           }
4537         }
4538       } else {
4539         if (comps) {
4540           for (b = 0; b < fdof; b++) {
4541             ncSet = fcSet = PETSC_FALSE;
4542             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4543             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4544             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4545           }
4546         } else {
4547           for (b = 0; b < fdof; b++) {
4548             if ((cind < fcdof) && (b == fcdofs[cind])) {
4549               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4550               ++cind;
4551             }
4552           }
4553         }
4554       }
4555     } else {
4556       if (perm) {
4557         if (comps) {
4558           for (b = 0; b < fdof; b++) {
4559             ncSet = fcSet = PETSC_FALSE;
4560             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4561             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4562             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4563           }
4564         } else {
4565           for (b = 0; b < fdof; b++) {
4566             if ((cind < fcdof) && (b == fcdofs[cind])) {
4567               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4568               ++cind;
4569             }
4570           }
4571         }
4572       } else {
4573         if (comps) {
4574           for (b = 0; b < fdof; b++) {
4575             ncSet = fcSet = PETSC_FALSE;
4576             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4577             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4578             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4579           }
4580         } else {
4581           for (b = 0; b < fdof; b++) {
4582             if ((cind < fcdof) && (b == fcdofs[cind])) {
4583               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4584               ++cind;
4585             }
4586           }
4587         }
4588       }
4589     }
4590   }
4591   *offset += fdof;
4592   PetscFunctionReturn(0);
4593 }
4594 
4595 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4596 {
4597   PetscScalar    *array;
4598   const PetscInt *cone, *coneO;
4599   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4600   PetscErrorCode  ierr;
4601 
4602   PetscFunctionBeginHot;
4603   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4604   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
4605   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4606   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
4607   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4608   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4609     const PetscInt cp = !p ? point : cone[p-1];
4610     const PetscInt o  = !p ? 0     : coneO[p-1];
4611 
4612     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4613     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4614     /* ADD_VALUES */
4615     {
4616       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4617       PetscScalar    *a;
4618       PetscInt        cdof, coff, cind = 0, k;
4619 
4620       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
4621       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
4622       a    = &array[coff];
4623       if (!cdof) {
4624         if (o >= 0) {
4625           for (k = 0; k < dof; ++k) {
4626             a[k] += values[off+k];
4627           }
4628         } else {
4629           for (k = 0; k < dof; ++k) {
4630             a[k] += values[off+dof-k-1];
4631           }
4632         }
4633       } else {
4634         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
4635         if (o >= 0) {
4636           for (k = 0; k < dof; ++k) {
4637             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4638             a[k] += values[off+k];
4639           }
4640         } else {
4641           for (k = 0; k < dof; ++k) {
4642             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4643             a[k] += values[off+dof-k-1];
4644           }
4645         }
4646       }
4647     }
4648   }
4649   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4650   PetscFunctionReturn(0);
4651 }
4652 
4653 /*@C
4654   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4655 
4656   Not collective
4657 
4658   Input Parameters:
4659 + dm - The DM
4660 . section - The section describing the layout in v, or NULL to use the default section
4661 . v - The local vector
4662 . point - The point in the DM
4663 . values - The array of values
4664 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4665          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
4666 
4667   Fortran Notes:
4668   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4669 
4670   Level: intermediate
4671 
4672 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4673 @*/
4674 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4675 {
4676   PetscSection    clSection;
4677   IS              clPoints;
4678   PetscScalar    *array;
4679   PetscInt       *points = NULL;
4680   const PetscInt *clp, *clperm;
4681   PetscInt        depth, numFields, numPoints, p;
4682   PetscErrorCode  ierr;
4683 
4684   PetscFunctionBeginHot;
4685   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4686   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
4687   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4688   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4689   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4690   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4691   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4692     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
4693     PetscFunctionReturn(0);
4694   }
4695   /* Get points */
4696   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
4697   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4698   /* Get array */
4699   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4700   /* Get values */
4701   if (numFields > 0) {
4702     PetscInt offset = 0, f;
4703     for (f = 0; f < numFields; ++f) {
4704       const PetscInt    **perms = NULL;
4705       const PetscScalar **flips = NULL;
4706 
4707       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4708       switch (mode) {
4709       case INSERT_VALUES:
4710         for (p = 0; p < numPoints; p++) {
4711           const PetscInt    point = points[2*p];
4712           const PetscInt    *perm = perms ? perms[p] : NULL;
4713           const PetscScalar *flip = flips ? flips[p] : NULL;
4714           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4715         } break;
4716       case INSERT_ALL_VALUES:
4717         for (p = 0; p < numPoints; p++) {
4718           const PetscInt    point = points[2*p];
4719           const PetscInt    *perm = perms ? perms[p] : NULL;
4720           const PetscScalar *flip = flips ? flips[p] : NULL;
4721           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4722         } break;
4723       case INSERT_BC_VALUES:
4724         for (p = 0; p < numPoints; p++) {
4725           const PetscInt    point = points[2*p];
4726           const PetscInt    *perm = perms ? perms[p] : NULL;
4727           const PetscScalar *flip = flips ? flips[p] : NULL;
4728           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4729         } break;
4730       case ADD_VALUES:
4731         for (p = 0; p < numPoints; p++) {
4732           const PetscInt    point = points[2*p];
4733           const PetscInt    *perm = perms ? perms[p] : NULL;
4734           const PetscScalar *flip = flips ? flips[p] : NULL;
4735           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4736         } break;
4737       case ADD_ALL_VALUES:
4738         for (p = 0; p < numPoints; p++) {
4739           const PetscInt    point = points[2*p];
4740           const PetscInt    *perm = perms ? perms[p] : NULL;
4741           const PetscScalar *flip = flips ? flips[p] : NULL;
4742           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4743         } break;
4744       case ADD_BC_VALUES:
4745         for (p = 0; p < numPoints; p++) {
4746           const PetscInt    point = points[2*p];
4747           const PetscInt    *perm = perms ? perms[p] : NULL;
4748           const PetscScalar *flip = flips ? flips[p] : NULL;
4749           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4750         } break;
4751       default:
4752         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4753       }
4754       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4755     }
4756   } else {
4757     PetscInt dof, off;
4758     const PetscInt    **perms = NULL;
4759     const PetscScalar **flips = NULL;
4760 
4761     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4762     switch (mode) {
4763     case INSERT_VALUES:
4764       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4765         const PetscInt    point = points[2*p];
4766         const PetscInt    *perm = perms ? perms[p] : NULL;
4767         const PetscScalar *flip = flips ? flips[p] : NULL;
4768         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4769         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4770       } break;
4771     case INSERT_ALL_VALUES:
4772       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4773         const PetscInt    point = points[2*p];
4774         const PetscInt    *perm = perms ? perms[p] : NULL;
4775         const PetscScalar *flip = flips ? flips[p] : NULL;
4776         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4777         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4778       } break;
4779     case INSERT_BC_VALUES:
4780       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4781         const PetscInt    point = points[2*p];
4782         const PetscInt    *perm = perms ? perms[p] : NULL;
4783         const PetscScalar *flip = flips ? flips[p] : NULL;
4784         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4785         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4786       } break;
4787     case ADD_VALUES:
4788       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4789         const PetscInt    point = points[2*p];
4790         const PetscInt    *perm = perms ? perms[p] : NULL;
4791         const PetscScalar *flip = flips ? flips[p] : NULL;
4792         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4793         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4794       } break;
4795     case ADD_ALL_VALUES:
4796       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4797         const PetscInt    point = points[2*p];
4798         const PetscInt    *perm = perms ? perms[p] : NULL;
4799         const PetscScalar *flip = flips ? flips[p] : NULL;
4800         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4801         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4802       } break;
4803     case ADD_BC_VALUES:
4804       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4805         const PetscInt    point = points[2*p];
4806         const PetscInt    *perm = perms ? perms[p] : NULL;
4807         const PetscScalar *flip = flips ? flips[p] : NULL;
4808         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4809         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4810       } break;
4811     default:
4812       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4813     }
4814     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4815   }
4816   /* Cleanup points */
4817   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4818   /* Cleanup array */
4819   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4820   PetscFunctionReturn(0);
4821 }
4822 
4823 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4824 {
4825   PetscSection      clSection;
4826   IS                clPoints;
4827   PetscScalar       *array;
4828   PetscInt          *points = NULL;
4829   const PetscInt    *clp, *clperm;
4830   PetscInt          numFields, numPoints, p;
4831   PetscInt          offset = 0, f;
4832   PetscErrorCode    ierr;
4833 
4834   PetscFunctionBeginHot;
4835   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4836   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
4837   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4838   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4839   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4840   /* Get points */
4841   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
4842   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4843   /* Get array */
4844   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4845   /* Get values */
4846   for (f = 0; f < numFields; ++f) {
4847     const PetscInt    **perms = NULL;
4848     const PetscScalar **flips = NULL;
4849 
4850     if (!fieldActive[f]) {
4851       for (p = 0; p < numPoints*2; p += 2) {
4852         PetscInt fdof;
4853         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4854         offset += fdof;
4855       }
4856       continue;
4857     }
4858     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4859     switch (mode) {
4860     case INSERT_VALUES:
4861       for (p = 0; p < numPoints; p++) {
4862         const PetscInt    point = points[2*p];
4863         const PetscInt    *perm = perms ? perms[p] : NULL;
4864         const PetscScalar *flip = flips ? flips[p] : NULL;
4865         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4866       } break;
4867     case INSERT_ALL_VALUES:
4868       for (p = 0; p < numPoints; p++) {
4869         const PetscInt    point = points[2*p];
4870         const PetscInt    *perm = perms ? perms[p] : NULL;
4871         const PetscScalar *flip = flips ? flips[p] : NULL;
4872         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4873         } break;
4874     case INSERT_BC_VALUES:
4875       for (p = 0; p < numPoints; p++) {
4876         const PetscInt    point = points[2*p];
4877         const PetscInt    *perm = perms ? perms[p] : NULL;
4878         const PetscScalar *flip = flips ? flips[p] : NULL;
4879         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4880       } break;
4881     case ADD_VALUES:
4882       for (p = 0; p < numPoints; p++) {
4883         const PetscInt    point = points[2*p];
4884         const PetscInt    *perm = perms ? perms[p] : NULL;
4885         const PetscScalar *flip = flips ? flips[p] : NULL;
4886         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4887       } break;
4888     case ADD_ALL_VALUES:
4889       for (p = 0; p < numPoints; p++) {
4890         const PetscInt    point = points[2*p];
4891         const PetscInt    *perm = perms ? perms[p] : NULL;
4892         const PetscScalar *flip = flips ? flips[p] : NULL;
4893         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4894       } break;
4895     default:
4896       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4897     }
4898     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4899   }
4900   /* Cleanup points */
4901   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4902   /* Cleanup array */
4903   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4904   PetscFunctionReturn(0);
4905 }
4906 
4907 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4908 {
4909   PetscMPIInt    rank;
4910   PetscInt       i, j;
4911   PetscErrorCode ierr;
4912 
4913   PetscFunctionBegin;
4914   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
4915   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr);
4916   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
4917   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
4918   numCIndices = numCIndices ? numCIndices : numRIndices;
4919   for (i = 0; i < numRIndices; i++) {
4920     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
4921     for (j = 0; j < numCIndices; j++) {
4922 #if defined(PETSC_USE_COMPLEX)
4923       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
4924 #else
4925       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
4926 #endif
4927     }
4928     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
4929   }
4930   PetscFunctionReturn(0);
4931 }
4932 
4933 /* . off - The global offset of this point */
4934 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4935 {
4936   PetscInt        dof;    /* The number of unknowns on this point */
4937   PetscInt        cdof;   /* The number of constraints on this point */
4938   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4939   PetscInt        cind = 0, k;
4940   PetscErrorCode  ierr;
4941 
4942   PetscFunctionBegin;
4943   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4944   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4945   if (!cdof || setBC) {
4946     if (perm) {
4947       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4948     } else {
4949       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4950     }
4951   } else {
4952     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4953     if (perm) {
4954       for (k = 0; k < dof; ++k) {
4955         if ((cind < cdof) && (k == cdofs[cind])) {
4956           /* Insert check for returning constrained indices */
4957           indices[*loff+perm[k]] = -(off+k+1);
4958           ++cind;
4959         } else {
4960           indices[*loff+perm[k]] = off+k-cind;
4961         }
4962       }
4963     } else {
4964       for (k = 0; k < dof; ++k) {
4965         if ((cind < cdof) && (k == cdofs[cind])) {
4966           /* Insert check for returning constrained indices */
4967           indices[*loff+k] = -(off+k+1);
4968           ++cind;
4969         } else {
4970           indices[*loff+k] = off+k-cind;
4971         }
4972       }
4973     }
4974   }
4975   *loff += dof;
4976   PetscFunctionReturn(0);
4977 }
4978 
4979 /*
4980   This version only believes the point offset from the globalSection
4981 
4982  . off - The global offset of this point
4983 */
4984 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4985 {
4986   PetscInt       numFields, foff, f;
4987   PetscErrorCode ierr;
4988 
4989   PetscFunctionBegin;
4990   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4991   for (f = 0, foff = 0; f < numFields; ++f) {
4992     PetscInt        fdof, cfdof;
4993     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4994     PetscInt        cind = 0, b;
4995     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
4996 
4997     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4998     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
4999     if (!cfdof || setBC) {
5000       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
5001       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
5002     } else {
5003       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5004       if (perm) {
5005         for (b = 0; b < fdof; b++) {
5006           if ((cind < cfdof) && (b == fcdofs[cind])) {
5007             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
5008             ++cind;
5009           } else {
5010             indices[foffs[f]+perm[b]] = off+foff+b-cind;
5011           }
5012         }
5013       } else {
5014         for (b = 0; b < fdof; b++) {
5015           if ((cind < cfdof) && (b == fcdofs[cind])) {
5016             indices[foffs[f]+b] = -(off+foff+b+1);
5017             ++cind;
5018           } else {
5019             indices[foffs[f]+b] = off+foff+b-cind;
5020           }
5021         }
5022       }
5023     }
5024     foff     += (setBC ? fdof : (fdof - cfdof));
5025     foffs[f] += fdof;
5026   }
5027   PetscFunctionReturn(0);
5028 }
5029 
5030 /*
5031   This version believes the globalSection offsets for each field, rather than just the point offset
5032 
5033  . foffs - The offset into 'indices' for each field, since it is segregated by field
5034 */
5035 PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
5036 {
5037   PetscInt       numFields, foff, f;
5038   PetscErrorCode ierr;
5039 
5040   PetscFunctionBegin;
5041   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5042   for (f = 0; f < numFields; ++f) {
5043     PetscInt        fdof, cfdof;
5044     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5045     PetscInt        cind = 0, b;
5046     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5047 
5048     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5049     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5050     ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr);
5051     if (!cfdof || setBC) {
5052       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = foff+b;}}
5053       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = foff+b;}}
5054     } else {
5055       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5056       if (perm) {
5057         for (b = 0; b < fdof; b++) {
5058           if ((cind < cfdof) && (b == fcdofs[cind])) {
5059             indices[foffs[f]+perm[b]] = -(foff+b+1);
5060             ++cind;
5061           } else {
5062             indices[foffs[f]+perm[b]] = foff+b-cind;
5063           }
5064         }
5065       } else {
5066         for (b = 0; b < fdof; b++) {
5067           if ((cind < cfdof) && (b == fcdofs[cind])) {
5068             indices[foffs[f]+b] = -(foff+b+1);
5069             ++cind;
5070           } else {
5071             indices[foffs[f]+b] = foff+b-cind;
5072           }
5073         }
5074       }
5075     }
5076     foffs[f] += fdof;
5077   }
5078   PetscFunctionReturn(0);
5079 }
5080 
5081 PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft)
5082 {
5083   Mat             cMat;
5084   PetscSection    aSec, cSec;
5085   IS              aIS;
5086   PetscInt        aStart = -1, aEnd = -1;
5087   const PetscInt  *anchors;
5088   PetscInt        numFields, f, p, q, newP = 0;
5089   PetscInt        newNumPoints = 0, newNumIndices = 0;
5090   PetscInt        *newPoints, *indices, *newIndices;
5091   PetscInt        maxAnchor, maxDof;
5092   PetscInt        newOffsets[32];
5093   PetscInt        *pointMatOffsets[32];
5094   PetscInt        *newPointOffsets[32];
5095   PetscScalar     *pointMat[32];
5096   PetscScalar     *newValues=NULL,*tmpValues;
5097   PetscBool       anyConstrained = PETSC_FALSE;
5098   PetscErrorCode  ierr;
5099 
5100   PetscFunctionBegin;
5101   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5102   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5103   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5104 
5105   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
5106   /* if there are point-to-point constraints */
5107   if (aSec) {
5108     ierr = PetscMemzero(newOffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5109     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
5110     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
5111     /* figure out how many points are going to be in the new element matrix
5112      * (we allow double counting, because it's all just going to be summed
5113      * into the global matrix anyway) */
5114     for (p = 0; p < 2*numPoints; p+=2) {
5115       PetscInt b    = points[p];
5116       PetscInt bDof = 0, bSecDof;
5117 
5118       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5119       if (!bSecDof) {
5120         continue;
5121       }
5122       if (b >= aStart && b < aEnd) {
5123         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
5124       }
5125       if (bDof) {
5126         /* this point is constrained */
5127         /* it is going to be replaced by its anchors */
5128         PetscInt bOff, q;
5129 
5130         anyConstrained = PETSC_TRUE;
5131         newNumPoints  += bDof;
5132         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
5133         for (q = 0; q < bDof; q++) {
5134           PetscInt a = anchors[bOff + q];
5135           PetscInt aDof;
5136 
5137           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
5138           newNumIndices += aDof;
5139           for (f = 0; f < numFields; ++f) {
5140             PetscInt fDof;
5141 
5142             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
5143             newOffsets[f+1] += fDof;
5144           }
5145         }
5146       }
5147       else {
5148         /* this point is not constrained */
5149         newNumPoints++;
5150         newNumIndices += bSecDof;
5151         for (f = 0; f < numFields; ++f) {
5152           PetscInt fDof;
5153 
5154           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5155           newOffsets[f+1] += fDof;
5156         }
5157       }
5158     }
5159   }
5160   if (!anyConstrained) {
5161     if (outNumPoints)  *outNumPoints  = 0;
5162     if (outNumIndices) *outNumIndices = 0;
5163     if (outPoints)     *outPoints     = NULL;
5164     if (outValues)     *outValues     = NULL;
5165     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
5166     PetscFunctionReturn(0);
5167   }
5168 
5169   if (outNumPoints)  *outNumPoints  = newNumPoints;
5170   if (outNumIndices) *outNumIndices = newNumIndices;
5171 
5172   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
5173 
5174   if (!outPoints && !outValues) {
5175     if (offsets) {
5176       for (f = 0; f <= numFields; f++) {
5177         offsets[f] = newOffsets[f];
5178       }
5179     }
5180     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
5181     PetscFunctionReturn(0);
5182   }
5183 
5184   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
5185 
5186   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
5187 
5188   /* workspaces */
5189   if (numFields) {
5190     for (f = 0; f < numFields; f++) {
5191       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
5192       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
5193     }
5194   }
5195   else {
5196     ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
5197     ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
5198   }
5199 
5200   /* get workspaces for the point-to-point matrices */
5201   if (numFields) {
5202     PetscInt totalOffset, totalMatOffset;
5203 
5204     for (p = 0; p < numPoints; p++) {
5205       PetscInt b    = points[2*p];
5206       PetscInt bDof = 0, bSecDof;
5207 
5208       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5209       if (!bSecDof) {
5210         for (f = 0; f < numFields; f++) {
5211           newPointOffsets[f][p + 1] = 0;
5212           pointMatOffsets[f][p + 1] = 0;
5213         }
5214         continue;
5215       }
5216       if (b >= aStart && b < aEnd) {
5217         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5218       }
5219       if (bDof) {
5220         for (f = 0; f < numFields; f++) {
5221           PetscInt fDof, q, bOff, allFDof = 0;
5222 
5223           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5224           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5225           for (q = 0; q < bDof; q++) {
5226             PetscInt a = anchors[bOff + q];
5227             PetscInt aFDof;
5228 
5229             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
5230             allFDof += aFDof;
5231           }
5232           newPointOffsets[f][p+1] = allFDof;
5233           pointMatOffsets[f][p+1] = fDof * allFDof;
5234         }
5235       }
5236       else {
5237         for (f = 0; f < numFields; f++) {
5238           PetscInt fDof;
5239 
5240           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5241           newPointOffsets[f][p+1] = fDof;
5242           pointMatOffsets[f][p+1] = 0;
5243         }
5244       }
5245     }
5246     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5247       newPointOffsets[f][0] = totalOffset;
5248       pointMatOffsets[f][0] = totalMatOffset;
5249       for (p = 0; p < numPoints; p++) {
5250         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5251         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5252       }
5253       totalOffset    = newPointOffsets[f][numPoints];
5254       totalMatOffset = pointMatOffsets[f][numPoints];
5255       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
5256     }
5257   }
5258   else {
5259     for (p = 0; p < numPoints; p++) {
5260       PetscInt b    = points[2*p];
5261       PetscInt bDof = 0, bSecDof;
5262 
5263       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5264       if (!bSecDof) {
5265         newPointOffsets[0][p + 1] = 0;
5266         pointMatOffsets[0][p + 1] = 0;
5267         continue;
5268       }
5269       if (b >= aStart && b < aEnd) {
5270         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5271       }
5272       if (bDof) {
5273         PetscInt bOff, q, allDof = 0;
5274 
5275         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5276         for (q = 0; q < bDof; q++) {
5277           PetscInt a = anchors[bOff + q], aDof;
5278 
5279           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
5280           allDof += aDof;
5281         }
5282         newPointOffsets[0][p+1] = allDof;
5283         pointMatOffsets[0][p+1] = bSecDof * allDof;
5284       }
5285       else {
5286         newPointOffsets[0][p+1] = bSecDof;
5287         pointMatOffsets[0][p+1] = 0;
5288       }
5289     }
5290     newPointOffsets[0][0] = 0;
5291     pointMatOffsets[0][0] = 0;
5292     for (p = 0; p < numPoints; p++) {
5293       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5294       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5295     }
5296     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
5297   }
5298 
5299   /* output arrays */
5300   ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5301 
5302   /* get the point-to-point matrices; construct newPoints */
5303   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
5304   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
5305   ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
5306   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
5307   if (numFields) {
5308     for (p = 0, newP = 0; p < numPoints; p++) {
5309       PetscInt b    = points[2*p];
5310       PetscInt o    = points[2*p+1];
5311       PetscInt bDof = 0, bSecDof;
5312 
5313       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
5314       if (!bSecDof) {
5315         continue;
5316       }
5317       if (b >= aStart && b < aEnd) {
5318         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5319       }
5320       if (bDof) {
5321         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
5322 
5323         fStart[0] = 0;
5324         fEnd[0]   = 0;
5325         for (f = 0; f < numFields; f++) {
5326           PetscInt fDof;
5327 
5328           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
5329           fStart[f+1] = fStart[f] + fDof;
5330           fEnd[f+1]   = fStart[f+1];
5331         }
5332         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
5333         ierr = DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);CHKERRQ(ierr);
5334 
5335         fAnchorStart[0] = 0;
5336         fAnchorEnd[0]   = 0;
5337         for (f = 0; f < numFields; f++) {
5338           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
5339 
5340           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5341           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5342         }
5343         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5344         for (q = 0; q < bDof; q++) {
5345           PetscInt a = anchors[bOff + q], aOff;
5346 
5347           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5348           newPoints[2*(newP + q)]     = a;
5349           newPoints[2*(newP + q) + 1] = 0;
5350           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
5351           ierr = DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);CHKERRQ(ierr);
5352         }
5353         newP += bDof;
5354 
5355         if (outValues) {
5356           /* get the point-to-point submatrix */
5357           for (f = 0; f < numFields; f++) {
5358             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
5359           }
5360         }
5361       }
5362       else {
5363         newPoints[2 * newP]     = b;
5364         newPoints[2 * newP + 1] = o;
5365         newP++;
5366       }
5367     }
5368   } else {
5369     for (p = 0; p < numPoints; p++) {
5370       PetscInt b    = points[2*p];
5371       PetscInt o    = points[2*p+1];
5372       PetscInt bDof = 0, bSecDof;
5373 
5374       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
5375       if (!bSecDof) {
5376         continue;
5377       }
5378       if (b >= aStart && b < aEnd) {
5379         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5380       }
5381       if (bDof) {
5382         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5383 
5384         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
5385         ierr = DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, indices);CHKERRQ(ierr);
5386 
5387         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
5388         for (q = 0; q < bDof; q++) {
5389           PetscInt a = anchors[bOff + q], aOff;
5390 
5391           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5392 
5393           newPoints[2*(newP + q)]     = a;
5394           newPoints[2*(newP + q) + 1] = 0;
5395           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
5396           ierr = DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);CHKERRQ(ierr);
5397         }
5398         newP += bDof;
5399 
5400         /* get the point-to-point submatrix */
5401         if (outValues) {
5402           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
5403         }
5404       }
5405       else {
5406         newPoints[2 * newP]     = b;
5407         newPoints[2 * newP + 1] = o;
5408         newP++;
5409       }
5410     }
5411   }
5412 
5413   if (outValues) {
5414     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
5415     ierr = PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));CHKERRQ(ierr);
5416     /* multiply constraints on the right */
5417     if (numFields) {
5418       for (f = 0; f < numFields; f++) {
5419         PetscInt oldOff = offsets[f];
5420 
5421         for (p = 0; p < numPoints; p++) {
5422           PetscInt cStart = newPointOffsets[f][p];
5423           PetscInt b      = points[2 * p];
5424           PetscInt c, r, k;
5425           PetscInt dof;
5426 
5427           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
5428           if (!dof) {
5429             continue;
5430           }
5431           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5432             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5433             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5434 
5435             for (r = 0; r < numIndices; r++) {
5436               for (c = 0; c < nCols; c++) {
5437                 for (k = 0; k < dof; k++) {
5438                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5439                 }
5440               }
5441             }
5442           }
5443           else {
5444             /* copy this column as is */
5445             for (r = 0; r < numIndices; r++) {
5446               for (c = 0; c < dof; c++) {
5447                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5448               }
5449             }
5450           }
5451           oldOff += dof;
5452         }
5453       }
5454     }
5455     else {
5456       PetscInt oldOff = 0;
5457       for (p = 0; p < numPoints; p++) {
5458         PetscInt cStart = newPointOffsets[0][p];
5459         PetscInt b      = points[2 * p];
5460         PetscInt c, r, k;
5461         PetscInt dof;
5462 
5463         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
5464         if (!dof) {
5465           continue;
5466         }
5467         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5468           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5469           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5470 
5471           for (r = 0; r < numIndices; r++) {
5472             for (c = 0; c < nCols; c++) {
5473               for (k = 0; k < dof; k++) {
5474                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5475               }
5476             }
5477           }
5478         }
5479         else {
5480           /* copy this column as is */
5481           for (r = 0; r < numIndices; r++) {
5482             for (c = 0; c < dof; c++) {
5483               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5484             }
5485           }
5486         }
5487         oldOff += dof;
5488       }
5489     }
5490 
5491     if (multiplyLeft) {
5492       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
5493       ierr = PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));CHKERRQ(ierr);
5494       /* multiply constraints transpose on the left */
5495       if (numFields) {
5496         for (f = 0; f < numFields; f++) {
5497           PetscInt oldOff = offsets[f];
5498 
5499           for (p = 0; p < numPoints; p++) {
5500             PetscInt rStart = newPointOffsets[f][p];
5501             PetscInt b      = points[2 * p];
5502             PetscInt c, r, k;
5503             PetscInt dof;
5504 
5505             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
5506             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5507               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
5508               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5509 
5510               for (r = 0; r < nRows; r++) {
5511                 for (c = 0; c < newNumIndices; c++) {
5512                   for (k = 0; k < dof; k++) {
5513                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5514                   }
5515                 }
5516               }
5517             }
5518             else {
5519               /* copy this row as is */
5520               for (r = 0; r < dof; r++) {
5521                 for (c = 0; c < newNumIndices; c++) {
5522                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5523                 }
5524               }
5525             }
5526             oldOff += dof;
5527           }
5528         }
5529       }
5530       else {
5531         PetscInt oldOff = 0;
5532 
5533         for (p = 0; p < numPoints; p++) {
5534           PetscInt rStart = newPointOffsets[0][p];
5535           PetscInt b      = points[2 * p];
5536           PetscInt c, r, k;
5537           PetscInt dof;
5538 
5539           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
5540           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5541             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
5542             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5543 
5544             for (r = 0; r < nRows; r++) {
5545               for (c = 0; c < newNumIndices; c++) {
5546                 for (k = 0; k < dof; k++) {
5547                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5548                 }
5549               }
5550             }
5551           }
5552           else {
5553             /* copy this row as is */
5554             for (r = 0; r < dof; r++) {
5555               for (c = 0; c < newNumIndices; c++) {
5556                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5557               }
5558             }
5559           }
5560           oldOff += dof;
5561         }
5562       }
5563 
5564       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
5565     }
5566     else {
5567       newValues = tmpValues;
5568     }
5569   }
5570 
5571   /* clean up */
5572   ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
5573   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
5574 
5575   if (numFields) {
5576     for (f = 0; f < numFields; f++) {
5577       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
5578       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
5579       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
5580     }
5581   }
5582   else {
5583     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
5584     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
5585     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
5586   }
5587   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
5588 
5589   /* output */
5590   if (outPoints) {
5591     *outPoints = newPoints;
5592   }
5593   else {
5594     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5595   }
5596   if (outValues) {
5597     *outValues = newValues;
5598   }
5599   for (f = 0; f <= numFields; f++) {
5600     offsets[f] = newOffsets[f];
5601   }
5602   PetscFunctionReturn(0);
5603 }
5604 
5605 /*@C
5606   DMPlexGetClosureIndices - Get the global indices in a vector v for all points in the closure of the given point
5607 
5608   Not collective
5609 
5610   Input Parameters:
5611 + dm - The DM
5612 . section - The section describing the layout in v, or NULL to use the default section
5613 . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5614 - point - The mesh point
5615 
5616   Output parameters:
5617 + numIndices - The number of indices
5618 . indices - The indices
5619 - outOffsets - Field offset if not NULL
5620 
5621   Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5622 
5623   Level: advanced
5624 
5625 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5626 @*/
5627 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5628 {
5629   PetscSection    clSection;
5630   IS              clPoints;
5631   const PetscInt *clp;
5632   const PetscInt  **perms[32] = {NULL};
5633   PetscInt       *points = NULL, *pointsNew;
5634   PetscInt        numPoints, numPointsNew;
5635   PetscInt        offsets[32];
5636   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5637   PetscErrorCode  ierr;
5638 
5639   PetscFunctionBegin;
5640   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5641   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5642   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5643   if (numIndices) PetscValidPointer(numIndices, 4);
5644   PetscValidPointer(indices, 5);
5645   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
5646   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5647   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5648   /* Get points in closure */
5649   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5650   /* Get number of indices and indices per field */
5651   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5652     PetscInt dof, fdof;
5653 
5654     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5655     for (f = 0; f < Nf; ++f) {
5656       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5657       offsets[f+1] += fdof;
5658     }
5659     Nind += dof;
5660   }
5661   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5662   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5663   if (!Nf) offsets[1] = Nind;
5664   /* Get dual space symmetries */
5665   for (f = 0; f < PetscMax(1,Nf); f++) {
5666     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5667     else    {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5668   }
5669   /* Correct for hanging node constraints */
5670   {
5671     ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
5672     if (numPointsNew) {
5673       for (f = 0; f < PetscMax(1,Nf); f++) {
5674         if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5675         else    {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5676       }
5677       for (f = 0; f < PetscMax(1,Nf); f++) {
5678         if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);}
5679         else    {ierr = PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);}
5680       }
5681       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5682       numPoints = numPointsNew;
5683       Nind      = NindNew;
5684       points    = pointsNew;
5685     }
5686   }
5687   /* Calculate indices */
5688   ierr = DMGetWorkArray(dm, Nind, MPIU_INT, indices);CHKERRQ(ierr);
5689   if (Nf) {
5690     if (outOffsets) {
5691       PetscInt f;
5692 
5693       for (f = 0; f <= Nf; f++) {
5694         outOffsets[f] = offsets[f];
5695       }
5696     }
5697     for (p = 0; p < numPoints; p++) {
5698       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5699       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5700     }
5701   } else {
5702     for (p = 0, off = 0; p < numPoints; p++) {
5703       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5704 
5705       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5706       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5707     }
5708   }
5709   /* Cleanup points */
5710   for (f = 0; f < PetscMax(1,Nf); f++) {
5711     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5712     else    {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5713   }
5714   if (numPointsNew) {
5715     ierr = DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);CHKERRQ(ierr);
5716   } else {
5717     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5718   }
5719   if (numIndices) *numIndices = Nind;
5720   PetscFunctionReturn(0);
5721 }
5722 
5723 /*@C
5724   DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5725 
5726   Not collective
5727 
5728   Input Parameters:
5729 + dm - The DM
5730 . section - The section describing the layout in v, or NULL to use the default section
5731 . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5732 . point - The mesh point
5733 . numIndices - The number of indices
5734 . indices - The indices
5735 - outOffsets - Field offset if not NULL
5736 
5737   Level: advanced
5738 
5739 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5740 @*/
5741 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5742 {
5743   PetscErrorCode ierr;
5744 
5745   PetscFunctionBegin;
5746   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5747   PetscValidPointer(indices, 5);
5748   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr);
5749   PetscFunctionReturn(0);
5750 }
5751 
5752 /*@C
5753   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5754 
5755   Not collective
5756 
5757   Input Parameters:
5758 + dm - The DM
5759 . section - The section describing the layout in v, or NULL to use the default section
5760 . globalSection - The section describing the layout in v, or NULL to use the default global section
5761 . A - The matrix
5762 . point - The point in the DM
5763 . values - The array of values
5764 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5765 
5766   Fortran Notes:
5767   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5768 
5769   Level: intermediate
5770 
5771 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5772 @*/
5773 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5774 {
5775   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5776   PetscSection        clSection;
5777   IS                  clPoints;
5778   PetscInt           *points = NULL, *newPoints;
5779   const PetscInt     *clp;
5780   PetscInt           *indices;
5781   PetscInt            offsets[32];
5782   const PetscInt    **perms[32] = {NULL};
5783   const PetscScalar **flips[32] = {NULL};
5784   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5785   PetscScalar        *valCopy = NULL;
5786   PetscScalar        *newValues;
5787   PetscErrorCode      ierr;
5788 
5789   PetscFunctionBegin;
5790   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5791   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
5792   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5793   if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
5794   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5795   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
5796   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5797   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5798   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5799   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5800   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5801     PetscInt fdof;
5802 
5803     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5804     for (f = 0; f < numFields; ++f) {
5805       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5806       offsets[f+1] += fdof;
5807     }
5808     numIndices += dof;
5809   }
5810   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5811 
5812   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5813   /* Get symmetries */
5814   for (f = 0; f < PetscMax(1,numFields); f++) {
5815     if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5816     else           {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5817     if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5818       PetscInt foffset = offsets[f];
5819 
5820       for (p = 0; p < numPoints; p++) {
5821         PetscInt point          = points[2*p], fdof;
5822         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
5823 
5824         if (!numFields) {
5825           ierr = PetscSectionGetDof(section,point,&fdof);CHKERRQ(ierr);
5826         } else {
5827           ierr = PetscSectionGetFieldDof(section,point,f,&fdof);CHKERRQ(ierr);
5828         }
5829         if (flip) {
5830           PetscInt i, j, k;
5831 
5832           if (!valCopy) {
5833             ierr = DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
5834             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5835             values = valCopy;
5836           }
5837           for (i = 0; i < fdof; i++) {
5838             PetscScalar fval = flip[i];
5839 
5840             for (k = 0; k < numIndices; k++) {
5841               valCopy[numIndices * (foffset + i) + k] *= fval;
5842               valCopy[numIndices * k + (foffset + i)] *= fval;
5843             }
5844           }
5845         }
5846         foffset += fdof;
5847       }
5848     }
5849   }
5850   ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);CHKERRQ(ierr);
5851   if (newNumPoints) {
5852     if (valCopy) {
5853       ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
5854     }
5855     for (f = 0; f < PetscMax(1,numFields); f++) {
5856       if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5857       else           {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5858     }
5859     for (f = 0; f < PetscMax(1,numFields); f++) {
5860       if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);}
5861       else           {ierr = PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);}
5862     }
5863     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5864     numPoints  = newNumPoints;
5865     numIndices = newNumIndices;
5866     points     = newPoints;
5867     values     = newValues;
5868   }
5869   ierr = DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr);
5870   if (numFields) {
5871     PetscBool useFieldOffsets;
5872 
5873     ierr = PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);CHKERRQ(ierr);
5874     if (useFieldOffsets) {
5875       for (p = 0; p < numPoints; p++) {
5876         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, indices);
5877       }
5878     } else {
5879       for (p = 0; p < numPoints; p++) {
5880         ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5881         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5882       }
5883     }
5884   } else {
5885     for (p = 0, off = 0; p < numPoints; p++) {
5886       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5887       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5888       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5889     }
5890   }
5891   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
5892   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5893   if (mesh->printFEM > 1) {
5894     PetscInt i;
5895     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
5896     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
5897     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5898   }
5899   if (ierr) {
5900     PetscMPIInt    rank;
5901     PetscErrorCode ierr2;
5902 
5903     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5904     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5905     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5906     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5907     CHKERRQ(ierr);
5908   }
5909   for (f = 0; f < PetscMax(1,numFields); f++) {
5910     if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5911     else           {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5912   }
5913   if (newNumPoints) {
5914     ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
5915     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5916   }
5917   else {
5918     if (valCopy) {
5919       ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
5920     }
5921     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5922   }
5923   ierr = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr);
5924   PetscFunctionReturn(0);
5925 }
5926 
5927 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5928 {
5929   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5930   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5931   PetscInt       *cpoints = NULL;
5932   PetscInt       *findices, *cindices;
5933   PetscInt        foffsets[32], coffsets[32];
5934   CellRefiner     cellRefiner;
5935   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5936   PetscErrorCode  ierr;
5937 
5938   PetscFunctionBegin;
5939   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
5940   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
5941   if (!fsection) {ierr = DMGetSection(dmf, &fsection);CHKERRQ(ierr);}
5942   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
5943   if (!csection) {ierr = DMGetSection(dmc, &csection);CHKERRQ(ierr);}
5944   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
5945   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
5946   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
5947   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
5948   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
5949   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
5950   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
5951   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5952   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5953   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5954   /* Column indices */
5955   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5956   maxFPoints = numCPoints;
5957   /* Compress out points not in the section */
5958   /*   TODO: Squeeze out points with 0 dof as well */
5959   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
5960   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5961     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5962       cpoints[q*2]   = cpoints[p];
5963       cpoints[q*2+1] = cpoints[p+1];
5964       ++q;
5965     }
5966   }
5967   numCPoints = q;
5968   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5969     PetscInt fdof;
5970 
5971     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
5972     if (!dof) continue;
5973     for (f = 0; f < numFields; ++f) {
5974       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
5975       coffsets[f+1] += fdof;
5976     }
5977     numCIndices += dof;
5978   }
5979   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5980   /* Row indices */
5981   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
5982   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
5983   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
5984   for (r = 0, q = 0; r < numSubcells; ++r) {
5985     /* TODO Map from coarse to fine cells */
5986     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5987     /* Compress out points not in the section */
5988     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
5989     for (p = 0; p < numFPoints*2; p += 2) {
5990       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5991         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
5992         if (!dof) continue;
5993         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5994         if (s < q) continue;
5995         ftotpoints[q*2]   = fpoints[p];
5996         ftotpoints[q*2+1] = fpoints[p+1];
5997         ++q;
5998       }
5999     }
6000     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6001   }
6002   numFPoints = q;
6003   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6004     PetscInt fdof;
6005 
6006     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
6007     if (!dof) continue;
6008     for (f = 0; f < numFields; ++f) {
6009       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
6010       foffsets[f+1] += fdof;
6011     }
6012     numFIndices += dof;
6013   }
6014   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6015 
6016   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6017   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6018   ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
6019   ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
6020   if (numFields) {
6021     const PetscInt **permsF[32] = {NULL};
6022     const PetscInt **permsC[32] = {NULL};
6023 
6024     for (f = 0; f < numFields; f++) {
6025       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6026       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6027     }
6028     for (p = 0; p < numFPoints; p++) {
6029       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6030       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
6031     }
6032     for (p = 0; p < numCPoints; p++) {
6033       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6034       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6035     }
6036     for (f = 0; f < numFields; f++) {
6037       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6038       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6039     }
6040   } else {
6041     const PetscInt **permsF = NULL;
6042     const PetscInt **permsC = NULL;
6043 
6044     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6045     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6046     for (p = 0, off = 0; p < numFPoints; p++) {
6047       const PetscInt *perm = permsF ? permsF[p] : NULL;
6048 
6049       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6050       ierr = DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);CHKERRQ(ierr);
6051     }
6052     for (p = 0, off = 0; p < numCPoints; p++) {
6053       const PetscInt *perm = permsC ? permsC[p] : NULL;
6054 
6055       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6056       ierr = DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);CHKERRQ(ierr);
6057     }
6058     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6059     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6060   }
6061   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
6062   /* TODO: flips */
6063   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6064   if (ierr) {
6065     PetscMPIInt    rank;
6066     PetscErrorCode ierr2;
6067 
6068     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6069     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6070     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6071     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6072     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6073     CHKERRQ(ierr);
6074   }
6075   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6076   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6077   ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
6078   ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
6079   PetscFunctionReturn(0);
6080 }
6081 
6082 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6083 {
6084   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
6085   PetscInt      *cpoints = NULL;
6086   PetscInt       foffsets[32], coffsets[32];
6087   CellRefiner    cellRefiner;
6088   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6089   PetscErrorCode ierr;
6090 
6091   PetscFunctionBegin;
6092   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
6093   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
6094   if (!fsection) {ierr = DMGetSection(dmf, &fsection);CHKERRQ(ierr);}
6095   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
6096   if (!csection) {ierr = DMGetSection(dmc, &csection);CHKERRQ(ierr);}
6097   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
6098   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
6099   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
6100   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
6101   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
6102   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
6103   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6104   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6105   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6106   /* Column indices */
6107   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6108   maxFPoints = numCPoints;
6109   /* Compress out points not in the section */
6110   /*   TODO: Squeeze out points with 0 dof as well */
6111   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
6112   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6113     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6114       cpoints[q*2]   = cpoints[p];
6115       cpoints[q*2+1] = cpoints[p+1];
6116       ++q;
6117     }
6118   }
6119   numCPoints = q;
6120   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6121     PetscInt fdof;
6122 
6123     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
6124     if (!dof) continue;
6125     for (f = 0; f < numFields; ++f) {
6126       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
6127       coffsets[f+1] += fdof;
6128     }
6129     numCIndices += dof;
6130   }
6131   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6132   /* Row indices */
6133   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
6134   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
6135   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6136   for (r = 0, q = 0; r < numSubcells; ++r) {
6137     /* TODO Map from coarse to fine cells */
6138     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6139     /* Compress out points not in the section */
6140     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
6141     for (p = 0; p < numFPoints*2; p += 2) {
6142       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6143         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
6144         if (!dof) continue;
6145         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6146         if (s < q) continue;
6147         ftotpoints[q*2]   = fpoints[p];
6148         ftotpoints[q*2+1] = fpoints[p+1];
6149         ++q;
6150       }
6151     }
6152     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6153   }
6154   numFPoints = q;
6155   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6156     PetscInt fdof;
6157 
6158     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
6159     if (!dof) continue;
6160     for (f = 0; f < numFields; ++f) {
6161       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
6162       foffsets[f+1] += fdof;
6163     }
6164     numFIndices += dof;
6165   }
6166   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6167 
6168   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6169   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6170   if (numFields) {
6171     const PetscInt **permsF[32] = {NULL};
6172     const PetscInt **permsC[32] = {NULL};
6173 
6174     for (f = 0; f < numFields; f++) {
6175       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6176       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6177     }
6178     for (p = 0; p < numFPoints; p++) {
6179       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6180       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
6181     }
6182     for (p = 0; p < numCPoints; p++) {
6183       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6184       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6185     }
6186     for (f = 0; f < numFields; f++) {
6187       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6188       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6189     }
6190   } else {
6191     const PetscInt **permsF = NULL;
6192     const PetscInt **permsC = NULL;
6193 
6194     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6195     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6196     for (p = 0, off = 0; p < numFPoints; p++) {
6197       const PetscInt *perm = permsF ? permsF[p] : NULL;
6198 
6199       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6200       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6201     }
6202     for (p = 0, off = 0; p < numCPoints; p++) {
6203       const PetscInt *perm = permsC ? permsC[p] : NULL;
6204 
6205       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6206       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6207     }
6208     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6209     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6210   }
6211   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6212   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6213   PetscFunctionReturn(0);
6214 }
6215 
6216 /*@
6217   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
6218 
6219   Input Parameter:
6220 . dm - The DMPlex object
6221 
6222   Output Parameters:
6223 + cMax - The first hybrid cell
6224 . fMax - The first hybrid face
6225 . eMax - The first hybrid edge
6226 - vMax - The first hybrid vertex
6227 
6228   Level: developer
6229 
6230 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6231 @*/
6232 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6233 {
6234   DM_Plex       *mesh = (DM_Plex*) dm->data;
6235   PetscInt       dim;
6236   PetscErrorCode ierr;
6237 
6238   PetscFunctionBegin;
6239   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6240   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6241   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6242   if (cMax) *cMax = mesh->hybridPointMax[dim];
6243   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6244   if (eMax) *eMax = mesh->hybridPointMax[1];
6245   if (vMax) *vMax = mesh->hybridPointMax[0];
6246   PetscFunctionReturn(0);
6247 }
6248 
6249 static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6250 {
6251   IS             is, his;
6252   PetscInt       first = 0, stride;
6253   PetscBool      isStride;
6254   PetscErrorCode ierr;
6255 
6256   PetscFunctionBegin;
6257   ierr = DMLabelGetStratumIS(depthLabel, d, &is);CHKERRQ(ierr);
6258   ierr = PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);CHKERRQ(ierr);
6259   if (isStride) {
6260     ierr = ISStrideGetInfo(is, &first, &stride);CHKERRQ(ierr);
6261   }
6262   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6263   ierr = ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);CHKERRQ(ierr);
6264   ierr = DMLabelSetStratumIS(dimLabel, d, his);CHKERRQ(ierr);
6265   ierr = ISDestroy(&his);CHKERRQ(ierr);
6266   ierr = ISDestroy(&is);CHKERRQ(ierr);
6267   PetscFunctionReturn(0);
6268 }
6269 
6270 /*@
6271   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
6272 
6273   Input Parameters:
6274 . dm   - The DMPlex object
6275 . cMax - The first hybrid cell
6276 . fMax - The first hybrid face
6277 . eMax - The first hybrid edge
6278 - vMax - The first hybrid vertex
6279 
6280   Level: developer
6281 
6282 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6283 @*/
6284 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6285 {
6286   DM_Plex       *mesh = (DM_Plex*) dm->data;
6287   PetscInt       dim;
6288   PetscErrorCode ierr;
6289 
6290   PetscFunctionBegin;
6291   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6292   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6293   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6294   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6295   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6296   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6297   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6298   PetscFunctionReturn(0);
6299 }
6300 
6301 /*@C
6302   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
6303 
6304   Input Parameter:
6305 . dm   - The DMPlex object
6306 
6307   Output Parameter:
6308 . cellHeight - The height of a cell
6309 
6310   Level: developer
6311 
6312 .seealso DMPlexSetVTKCellHeight()
6313 @*/
6314 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6315 {
6316   DM_Plex *mesh = (DM_Plex*) dm->data;
6317 
6318   PetscFunctionBegin;
6319   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6320   PetscValidPointer(cellHeight, 2);
6321   *cellHeight = mesh->vtkCellHeight;
6322   PetscFunctionReturn(0);
6323 }
6324 
6325 /*@C
6326   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
6327 
6328   Input Parameters:
6329 + dm   - The DMPlex object
6330 - cellHeight - The height of a cell
6331 
6332   Level: developer
6333 
6334 .seealso DMPlexGetVTKCellHeight()
6335 @*/
6336 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6337 {
6338   DM_Plex *mesh = (DM_Plex*) dm->data;
6339 
6340   PetscFunctionBegin;
6341   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6342   mesh->vtkCellHeight = cellHeight;
6343   PetscFunctionReturn(0);
6344 }
6345 
6346 /* We can easily have a form that takes an IS instead */
6347 static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6348 {
6349   PetscSection   section, globalSection;
6350   PetscInt      *numbers, p;
6351   PetscErrorCode ierr;
6352 
6353   PetscFunctionBegin;
6354   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6355   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
6356   for (p = pStart; p < pEnd; ++p) {
6357     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
6358   }
6359   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
6360   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6361   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
6362   for (p = pStart; p < pEnd; ++p) {
6363     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
6364     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6365     else                       numbers[p-pStart] += shift;
6366   }
6367   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
6368   if (globalSize) {
6369     PetscLayout layout;
6370     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
6371     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
6372     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
6373   }
6374   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6375   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
6376   PetscFunctionReturn(0);
6377 }
6378 
6379 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6380 {
6381   PetscInt       cellHeight, cStart, cEnd, cMax;
6382   PetscErrorCode ierr;
6383 
6384   PetscFunctionBegin;
6385   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
6386   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6387   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6388   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6389   ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
6390   PetscFunctionReturn(0);
6391 }
6392 
6393 /*@C
6394   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6395 
6396   Input Parameter:
6397 . dm   - The DMPlex object
6398 
6399   Output Parameter:
6400 . globalCellNumbers - Global cell numbers for all cells on this process
6401 
6402   Level: developer
6403 
6404 .seealso DMPlexGetVertexNumbering()
6405 @*/
6406 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6407 {
6408   DM_Plex       *mesh = (DM_Plex*) dm->data;
6409   PetscErrorCode ierr;
6410 
6411   PetscFunctionBegin;
6412   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6413   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
6414   *globalCellNumbers = mesh->globalCellNumbers;
6415   PetscFunctionReturn(0);
6416 }
6417 
6418 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6419 {
6420   PetscInt       vStart, vEnd, vMax;
6421   PetscErrorCode ierr;
6422 
6423   PetscFunctionBegin;
6424   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6425   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6426   ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
6427   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6428   ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
6429   PetscFunctionReturn(0);
6430 }
6431 
6432 /*@C
6433   DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process
6434 
6435   Input Parameter:
6436 . dm   - The DMPlex object
6437 
6438   Output Parameter:
6439 . globalVertexNumbers - Global vertex numbers for all vertices on this process
6440 
6441   Level: developer
6442 
6443 .seealso DMPlexGetCellNumbering()
6444 @*/
6445 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6446 {
6447   DM_Plex       *mesh = (DM_Plex*) dm->data;
6448   PetscErrorCode ierr;
6449 
6450   PetscFunctionBegin;
6451   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6452   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
6453   *globalVertexNumbers = mesh->globalVertexNumbers;
6454   PetscFunctionReturn(0);
6455 }
6456 
6457 /*@C
6458   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6459 
6460   Input Parameter:
6461 . dm   - The DMPlex object
6462 
6463   Output Parameter:
6464 . globalPointNumbers - Global numbers for all points on this process
6465 
6466   Level: developer
6467 
6468 .seealso DMPlexGetCellNumbering()
6469 @*/
6470 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6471 {
6472   IS             nums[4];
6473   PetscInt       depths[4];
6474   PetscInt       depth, d, shift = 0;
6475   PetscErrorCode ierr;
6476 
6477   PetscFunctionBegin;
6478   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6479   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6480   /* For unstratified meshes use dim instead of depth */
6481   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
6482   depths[0] = depth; depths[1] = 0;
6483   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6484   for (d = 0; d <= depth; ++d) {
6485     PetscInt pStart, pEnd, gsize;
6486 
6487     ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr);
6488     ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
6489     shift += gsize;
6490   }
6491   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
6492   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
6493   PetscFunctionReturn(0);
6494 }
6495 
6496 
6497 /*@
6498   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
6499 
6500   Input Parameter:
6501 . dm - The DMPlex object
6502 
6503   Output Parameter:
6504 . ranks - The rank field
6505 
6506   Options Database Keys:
6507 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
6508 
6509   Level: intermediate
6510 
6511 .seealso: DMView()
6512 @*/
6513 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6514 {
6515   DM             rdm;
6516   PetscDS        prob;
6517   PetscFE        fe;
6518   PetscScalar   *r;
6519   PetscMPIInt    rank;
6520   PetscInt       dim, cStart, cEnd, c;
6521   PetscErrorCode ierr;
6522 
6523   PetscFunctionBeginUser;
6524   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
6525   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
6526   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
6527   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, NULL, -1, &fe);CHKERRQ(ierr);
6528   ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr);
6529   ierr = DMGetDS(rdm, &prob);CHKERRQ(ierr);
6530   ierr = PetscDSSetDiscretization(prob, 0, (PetscObject) fe);CHKERRQ(ierr);
6531   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
6532   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6533   ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr);
6534   ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr);
6535   ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr);
6536   for (c = cStart; c < cEnd; ++c) {
6537     PetscScalar *lr;
6538 
6539     ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr);
6540     *lr = rank;
6541   }
6542   ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr);
6543   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
6544   PetscFunctionReturn(0);
6545 }
6546 
6547 /*@
6548   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6549 
6550   Input Parameter:
6551 . dm - The DMPlex object
6552 
6553   Note: This is a useful diagnostic when creating meshes programmatically.
6554 
6555   Level: developer
6556 
6557 .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6558 @*/
6559 PetscErrorCode DMPlexCheckSymmetry(DM dm)
6560 {
6561   PetscSection    coneSection, supportSection;
6562   const PetscInt *cone, *support;
6563   PetscInt        coneSize, c, supportSize, s;
6564   PetscInt        pStart, pEnd, p, csize, ssize;
6565   PetscErrorCode  ierr;
6566 
6567   PetscFunctionBegin;
6568   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6569   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
6570   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
6571   /* Check that point p is found in the support of its cone points, and vice versa */
6572   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6573   for (p = pStart; p < pEnd; ++p) {
6574     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
6575     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
6576     for (c = 0; c < coneSize; ++c) {
6577       PetscBool dup = PETSC_FALSE;
6578       PetscInt  d;
6579       for (d = c-1; d >= 0; --d) {
6580         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6581       }
6582       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
6583       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
6584       for (s = 0; s < supportSize; ++s) {
6585         if (support[s] == p) break;
6586       }
6587       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6588         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
6589         for (s = 0; s < coneSize; ++s) {
6590           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
6591         }
6592         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6593         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
6594         for (s = 0; s < supportSize; ++s) {
6595           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
6596         }
6597         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6598         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6599         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6600       }
6601     }
6602     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
6603     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
6604     for (s = 0; s < supportSize; ++s) {
6605       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6606       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6607       for (c = 0; c < coneSize; ++c) {
6608         if (cone[c] == p) break;
6609       }
6610       if (c >= coneSize) {
6611         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
6612         for (c = 0; c < supportSize; ++c) {
6613           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
6614         }
6615         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6616         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
6617         for (c = 0; c < coneSize; ++c) {
6618           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
6619         }
6620         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6621         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6622       }
6623     }
6624   }
6625   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
6626   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
6627   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6628   PetscFunctionReturn(0);
6629 }
6630 
6631 /*@
6632   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6633 
6634   Input Parameters:
6635 + dm - The DMPlex object
6636 . isSimplex - Are the cells simplices or tensor products
6637 - cellHeight - Normally 0
6638 
6639   Note: This is a useful diagnostic when creating meshes programmatically.
6640 
6641   Level: developer
6642 
6643 .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6644 @*/
6645 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6646 {
6647   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6648   PetscErrorCode ierr;
6649 
6650   PetscFunctionBegin;
6651   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6652   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6653   switch (dim) {
6654   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6655   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6656   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6657   default:
6658     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6659   }
6660   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6661   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6662   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6663   cMax = cMax >= 0 ? cMax : cEnd;
6664   for (c = cStart; c < cMax; ++c) {
6665     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6666 
6667     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6668     for (cl = 0; cl < closureSize*2; cl += 2) {
6669       const PetscInt p = closure[cl];
6670       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6671     }
6672     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6673     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6674   }
6675   for (c = cMax; c < cEnd; ++c) {
6676     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6677 
6678     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6679     for (cl = 0; cl < closureSize*2; cl += 2) {
6680       const PetscInt p = closure[cl];
6681       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6682     }
6683     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6684     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6685   }
6686   PetscFunctionReturn(0);
6687 }
6688 
6689 /*@
6690   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6691 
6692   Input Parameters:
6693 + dm - The DMPlex object
6694 . isSimplex - Are the cells simplices or tensor products
6695 - cellHeight - Normally 0
6696 
6697   Note: This is a useful diagnostic when creating meshes programmatically.
6698 
6699   Level: developer
6700 
6701 .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6702 @*/
6703 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6704 {
6705   PetscInt       pMax[4];
6706   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;
6707   PetscErrorCode ierr;
6708 
6709   PetscFunctionBegin;
6710   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6711   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6712   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6713   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
6714   for (h = cellHeight; h < dim; ++h) {
6715     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
6716     for (c = cStart; c < cEnd; ++c) {
6717       const PetscInt *cone, *ornt, *faces;
6718       PetscInt        numFaces, faceSize, coneSize,f;
6719       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
6720 
6721       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6722       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6723       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6724       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6725       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6726       for (cl = 0; cl < closureSize*2; cl += 2) {
6727         const PetscInt p = closure[cl];
6728         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6729       }
6730       ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
6731       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6732       for (f = 0; f < numFaces; ++f) {
6733         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6734 
6735         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
6736         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6737           const PetscInt p = fclosure[cl];
6738           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6739         }
6740         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);
6741         for (v = 0; v < fnumCorners; ++v) {
6742           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]);
6743         }
6744         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
6745       }
6746       ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
6747       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6748     }
6749   }
6750   PetscFunctionReturn(0);
6751 }
6752 
6753 static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
6754 {
6755   PetscInt i,l,n;
6756   const PetscInt *cone;
6757   PetscErrorCode ierr;
6758 
6759   PetscFunctionBegin;
6760   *missingPoint = -1;
6761   ierr = DMPlexGetConeSize(dm, p, &n);CHKERRQ(ierr);
6762   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
6763   for (i=0; i<n; i++) {
6764     ierr = PetscFindInt(cone[i], npoints, points, &l);CHKERRQ(ierr);
6765     if (l < 0) {
6766       *missingPoint = cone[i];
6767       break;
6768     }
6769   }
6770   PetscFunctionReturn(0);
6771 }
6772 
6773 /*@
6774   DMPlexCheckPointSF - Check that several sufficient conditions are met for the point SF of this plex.
6775 
6776   Input Parameters:
6777 . dm - The DMPlex object
6778 
6779   Note: This is mainly intended for debugging/testing purposes.
6780 
6781   Level: developer
6782 
6783 .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6784 @*/
6785 PetscErrorCode DMPlexCheckPointSF(DM dm)
6786 {
6787   PetscSF sf;
6788   PetscInt d,depth,i,nleaves,p,plo,phi,missingPoint;
6789   const PetscInt *locals;
6790   PetscErrorCode ierr;
6791 
6792   PetscFunctionBegin;
6793   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6794   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6795   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6796   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);CHKERRQ(ierr);
6797 
6798   /* 1) if some point is in interface, then all its cone points must be also in interface  */
6799   for (i=0; i<nleaves; i++) {
6800     p = locals[i];
6801     ierr = DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);CHKERRQ(ierr);
6802     if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
6803   }
6804 
6805   /* 2) check there are no faces in 2D, cells in 3D, in interface */
6806   ierr = DMPlexGetVTKCellHeight(dm, &d);CHKERRQ(ierr);
6807   ierr = DMPlexGetHeightStratum(dm, d, &plo, &phi);CHKERRQ(ierr);
6808   for (i=0; i<nleaves; i++) {
6809     p = locals[i];
6810     if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
6811   }
6812   PetscFunctionReturn(0);
6813 }
6814 
6815 /* Pointwise interpolation
6816      Just code FEM for now
6817      u^f = I u^c
6818      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6819      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6820      I_{ij} = psi^f_i phi^c_j
6821 */
6822 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6823 {
6824   PetscSection   gsc, gsf;
6825   PetscInt       m, n;
6826   void          *ctx;
6827   DM             cdm;
6828   PetscBool      regular, ismatis;
6829   PetscErrorCode ierr;
6830 
6831   PetscFunctionBegin;
6832   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
6833   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
6834   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
6835   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
6836 
6837   ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr);
6838   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
6839   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6840   ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr);
6841   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
6842 
6843   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
6844   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
6845   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
6846   else                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
6847   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
6848   /* Use naive scaling */
6849   ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
6850   PetscFunctionReturn(0);
6851 }
6852 
6853 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6854 {
6855   PetscErrorCode ierr;
6856   VecScatter     ctx;
6857 
6858   PetscFunctionBegin;
6859   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
6860   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
6861   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
6862   PetscFunctionReturn(0);
6863 }
6864 
6865 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6866 {
6867   PetscSection   gsc, gsf;
6868   PetscInt       m, n;
6869   void          *ctx;
6870   DM             cdm;
6871   PetscBool      regular;
6872   PetscErrorCode ierr;
6873 
6874   PetscFunctionBegin;
6875   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
6876   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
6877   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
6878   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
6879 
6880   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
6881   ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6882   ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
6883   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
6884 
6885   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
6886   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
6887   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
6888   else                            {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
6889   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
6890   PetscFunctionReturn(0);
6891 }
6892 
6893 PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6894 {
6895   PetscSection   section;
6896   IS            *bcPoints, *bcComps;
6897   PetscBool     *isFE;
6898   PetscInt      *bcFields, *numComp, *numDof;
6899   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6900   PetscInt       cStart, cEnd, cEndInterior;
6901   PetscErrorCode ierr;
6902 
6903   PetscFunctionBegin;
6904   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
6905   /* FE and FV boundary conditions are handled slightly differently */
6906   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
6907   for (f = 0; f < numFields; ++f) {
6908     PetscObject  obj;
6909     PetscClassId id;
6910 
6911     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
6912     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
6913     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6914     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6915     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6916   }
6917   /* Allocate boundary point storage for FEM boundaries */
6918   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6919   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6920   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6921   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
6922   ierr = PetscDSGetNumBoundary(dm->prob, &numBd);CHKERRQ(ierr);
6923   if (!numFields && numBd) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "number of fields is zero and number of boundary conditions is nonzero (this should never happen)");
6924   for (bd = 0; bd < numBd; ++bd) {
6925     PetscInt                field;
6926     DMBoundaryConditionType type;
6927     const char             *labelName;
6928     DMLabel                 label;
6929 
6930     ierr = PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
6931     ierr = DMGetLabel(dm,labelName,&label);CHKERRQ(ierr);
6932     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6933   }
6934   /* Add ghost cell boundaries for FVM */
6935   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6936   ierr = PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);CHKERRQ(ierr);
6937   /* Constrain ghost cells for FV */
6938   for (f = 0; f < numFields; ++f) {
6939     PetscInt *newidx, c;
6940 
6941     if (isFE[f] || cEndInterior < 0) continue;
6942     ierr = PetscMalloc1(cEnd-cEndInterior,&newidx);CHKERRQ(ierr);
6943     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6944     bcFields[bc] = f;
6945     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
6946   }
6947   /* Handle FEM Dirichlet boundaries */
6948   for (bd = 0; bd < numBd; ++bd) {
6949     const char             *bdLabel;
6950     DMLabel                 label;
6951     const PetscInt         *comps;
6952     const PetscInt         *values;
6953     PetscInt                bd2, field, numComps, numValues;
6954     DMBoundaryConditionType type;
6955     PetscBool               duplicate = PETSC_FALSE;
6956 
6957     ierr = PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);CHKERRQ(ierr);
6958     ierr = DMGetLabel(dm, bdLabel, &label);CHKERRQ(ierr);
6959     if (!isFE[field] || !label) continue;
6960     /* Only want to modify label once */
6961     for (bd2 = 0; bd2 < bd; ++bd2) {
6962       const char *bdname;
6963       ierr = PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
6964       ierr = PetscStrcmp(bdname, bdLabel, &duplicate);CHKERRQ(ierr);
6965       if (duplicate) break;
6966     }
6967     if (!duplicate && (isFE[field])) {
6968       /* don't complete cells, which are just present to give orientation to the boundary */
6969       ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr);
6970     }
6971     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6972     if (type & DM_BC_ESSENTIAL) {
6973       PetscInt       *newidx;
6974       PetscInt        n, newn = 0, p, v;
6975 
6976       bcFields[bc] = field;
6977       if (numComps) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);CHKERRQ(ierr);}
6978       for (v = 0; v < numValues; ++v) {
6979         IS              tmp;
6980         const PetscInt *idx;
6981 
6982         ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
6983         if (!tmp) continue;
6984         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
6985         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
6986         if (isFE[field]) {
6987           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6988         } else {
6989           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6990         }
6991         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
6992         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
6993       }
6994       ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr);
6995       newn = 0;
6996       for (v = 0; v < numValues; ++v) {
6997         IS              tmp;
6998         const PetscInt *idx;
6999 
7000         ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
7001         if (!tmp) continue;
7002         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
7003         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
7004         if (isFE[field]) {
7005           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
7006         } else {
7007           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
7008         }
7009         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
7010         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
7011       }
7012       ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
7013     }
7014   }
7015   /* Handle discretization */
7016   ierr = PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr);
7017   for (f = 0; f < numFields; ++f) {
7018     PetscObject obj;
7019 
7020     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
7021     if (isFE[f]) {
7022       PetscFE         fe = (PetscFE) obj;
7023       const PetscInt *numFieldDof;
7024       PetscInt        d;
7025 
7026       ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
7027       ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr);
7028       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
7029     } else {
7030       PetscFV fv = (PetscFV) obj;
7031 
7032       ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
7033       numDof[f*(dim+1)+dim] = numComp[f];
7034     }
7035   }
7036   for (f = 0; f < numFields; ++f) {
7037     PetscInt d;
7038     for (d = 1; d < dim; ++d) {
7039       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.");
7040     }
7041   }
7042   ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);CHKERRQ(ierr);
7043   for (f = 0; f < numFields; ++f) {
7044     PetscFE     fe;
7045     const char *name;
7046 
7047     ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr);
7048     ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr);
7049     ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr);
7050   }
7051   ierr = DMSetSection(dm, section);CHKERRQ(ierr);
7052   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7053   for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);ierr = ISDestroy(&bcComps[bc]);CHKERRQ(ierr);}
7054   ierr = PetscFree3(bcFields,bcPoints,bcComps);CHKERRQ(ierr);
7055   ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr);
7056   ierr = PetscFree(isFE);CHKERRQ(ierr);
7057   PetscFunctionReturn(0);
7058 }
7059 
7060 /*@
7061   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7062 
7063   Input Parameter:
7064 . dm - The DMPlex object
7065 
7066   Output Parameter:
7067 . regular - The flag
7068 
7069   Level: intermediate
7070 
7071 .seealso: DMPlexSetRegularRefinement()
7072 @*/
7073 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7074 {
7075   PetscFunctionBegin;
7076   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7077   PetscValidPointer(regular, 2);
7078   *regular = ((DM_Plex *) dm->data)->regularRefinement;
7079   PetscFunctionReturn(0);
7080 }
7081 
7082 /*@
7083   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7084 
7085   Input Parameters:
7086 + dm - The DMPlex object
7087 - regular - The flag
7088 
7089   Level: intermediate
7090 
7091 .seealso: DMPlexGetRegularRefinement()
7092 @*/
7093 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7094 {
7095   PetscFunctionBegin;
7096   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7097   ((DM_Plex *) dm->data)->regularRefinement = regular;
7098   PetscFunctionReturn(0);
7099 }
7100 
7101 /* anchors */
7102 /*@
7103   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
7104   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
7105 
7106   not collective
7107 
7108   Input Parameters:
7109 . dm - The DMPlex object
7110 
7111   Output Parameters:
7112 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
7113 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
7114 
7115 
7116   Level: intermediate
7117 
7118 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7119 @*/
7120 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7121 {
7122   DM_Plex *plex = (DM_Plex *)dm->data;
7123   PetscErrorCode ierr;
7124 
7125   PetscFunctionBegin;
7126   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7127   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
7128   if (anchorSection) *anchorSection = plex->anchorSection;
7129   if (anchorIS) *anchorIS = plex->anchorIS;
7130   PetscFunctionReturn(0);
7131 }
7132 
7133 /*@
7134   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
7135   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
7136   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
7137 
7138   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
7139   DMGetConstraints() and filling in the entries in the constraint matrix.
7140 
7141   collective on dm
7142 
7143   Input Parameters:
7144 + dm - The DMPlex object
7145 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.  Must have a local communicator (PETSC_COMM_SELF or derivative).
7146 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
7147 
7148   The reference counts of anchorSection and anchorIS are incremented.
7149 
7150   Level: intermediate
7151 
7152 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7153 @*/
7154 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7155 {
7156   DM_Plex        *plex = (DM_Plex *)dm->data;
7157   PetscMPIInt    result;
7158   PetscErrorCode ierr;
7159 
7160   PetscFunctionBegin;
7161   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7162   if (anchorSection) {
7163     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
7164     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr);
7165     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7166   }
7167   if (anchorIS) {
7168     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
7169     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr);
7170     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7171   }
7172 
7173   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
7174   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
7175   plex->anchorSection = anchorSection;
7176 
7177   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
7178   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
7179   plex->anchorIS = anchorIS;
7180 
7181 #if defined(PETSC_USE_DEBUG)
7182   if (anchorIS && anchorSection) {
7183     PetscInt size, a, pStart, pEnd;
7184     const PetscInt *anchors;
7185 
7186     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
7187     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
7188     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
7189     for (a = 0; a < size; a++) {
7190       PetscInt p;
7191 
7192       p = anchors[a];
7193       if (p >= pStart && p < pEnd) {
7194         PetscInt dof;
7195 
7196         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
7197         if (dof) {
7198           PetscErrorCode ierr2;
7199 
7200           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7201           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7202         }
7203       }
7204     }
7205     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
7206   }
7207 #endif
7208   /* reset the generic constraints */
7209   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
7210   PetscFunctionReturn(0);
7211 }
7212 
7213 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7214 {
7215   PetscSection anchorSection;
7216   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
7217   PetscErrorCode ierr;
7218 
7219   PetscFunctionBegin;
7220   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7221   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
7222   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
7223   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
7224   if (numFields) {
7225     PetscInt f;
7226     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
7227 
7228     for (f = 0; f < numFields; f++) {
7229       PetscInt numComp;
7230 
7231       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
7232       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
7233     }
7234   }
7235   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
7236   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
7237   pStart = PetscMax(pStart,sStart);
7238   pEnd   = PetscMin(pEnd,sEnd);
7239   pEnd   = PetscMax(pStart,pEnd);
7240   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
7241   for (p = pStart; p < pEnd; p++) {
7242     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
7243     if (dof) {
7244       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
7245       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
7246       for (f = 0; f < numFields; f++) {
7247         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
7248         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
7249       }
7250     }
7251   }
7252   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
7253   PetscFunctionReturn(0);
7254 }
7255 
7256 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7257 {
7258   PetscSection aSec;
7259   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7260   const PetscInt *anchors;
7261   PetscInt numFields, f;
7262   IS aIS;
7263   PetscErrorCode ierr;
7264 
7265   PetscFunctionBegin;
7266   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7267   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
7268   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
7269   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
7270   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
7271   ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr);
7272   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
7273   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
7274   /* cSec will be a subset of aSec and section */
7275   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
7276   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
7277   i[0] = 0;
7278   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
7279   for (p = pStart; p < pEnd; p++) {
7280     PetscInt rDof, rOff, r;
7281 
7282     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7283     if (!rDof) continue;
7284     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7285     if (numFields) {
7286       for (f = 0; f < numFields; f++) {
7287         annz = 0;
7288         for (r = 0; r < rDof; r++) {
7289           a = anchors[rOff + r];
7290           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
7291           annz += aDof;
7292         }
7293         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
7294         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
7295         for (q = 0; q < dof; q++) {
7296           i[off + q + 1] = i[off + q] + annz;
7297         }
7298       }
7299     }
7300     else {
7301       annz = 0;
7302       for (q = 0; q < dof; q++) {
7303         a = anchors[off + q];
7304         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
7305         annz += aDof;
7306       }
7307       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
7308       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
7309       for (q = 0; q < dof; q++) {
7310         i[off + q + 1] = i[off + q] + annz;
7311       }
7312     }
7313   }
7314   nnz = i[m];
7315   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
7316   offset = 0;
7317   for (p = pStart; p < pEnd; p++) {
7318     if (numFields) {
7319       for (f = 0; f < numFields; f++) {
7320         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
7321         for (q = 0; q < dof; q++) {
7322           PetscInt rDof, rOff, r;
7323           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7324           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7325           for (r = 0; r < rDof; r++) {
7326             PetscInt s;
7327 
7328             a = anchors[rOff + r];
7329             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
7330             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
7331             for (s = 0; s < aDof; s++) {
7332               j[offset++] = aOff + s;
7333             }
7334           }
7335         }
7336       }
7337     }
7338     else {
7339       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
7340       for (q = 0; q < dof; q++) {
7341         PetscInt rDof, rOff, r;
7342         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7343         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7344         for (r = 0; r < rDof; r++) {
7345           PetscInt s;
7346 
7347           a = anchors[rOff + r];
7348           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
7349           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
7350           for (s = 0; s < aDof; s++) {
7351             j[offset++] = aOff + s;
7352           }
7353         }
7354       }
7355     }
7356   }
7357   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
7358   ierr = PetscFree(i);CHKERRQ(ierr);
7359   ierr = PetscFree(j);CHKERRQ(ierr);
7360   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
7361   PetscFunctionReturn(0);
7362 }
7363 
7364 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7365 {
7366   DM_Plex        *plex = (DM_Plex *)dm->data;
7367   PetscSection   anchorSection, section, cSec;
7368   Mat            cMat;
7369   PetscErrorCode ierr;
7370 
7371   PetscFunctionBegin;
7372   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7373   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
7374   if (anchorSection) {
7375     PetscDS  ds;
7376     PetscInt nf;
7377 
7378     ierr = DMGetSection(dm,&section);CHKERRQ(ierr);
7379     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
7380     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
7381     ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
7382     ierr = PetscDSGetNumFields(ds,&nf);CHKERRQ(ierr);
7383     if (nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
7384     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
7385     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
7386     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
7387   }
7388   PetscFunctionReturn(0);
7389 }
7390 
7391 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7392 {
7393   PetscDS        prob;
7394   IS             subis;
7395   PetscSection   section, subsection;
7396   PetscErrorCode ierr;
7397 
7398   PetscFunctionBegin;
7399   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7400   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7401   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7402   /* Create subdomain */
7403   ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr);
7404   /* Create submodel */
7405   ierr = DMPlexCreateSubpointIS(*subdm, &subis);CHKERRQ(ierr);
7406   ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr);
7407   ierr = ISDestroy(&subis);CHKERRQ(ierr);
7408   ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
7409   ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
7410   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
7411   ierr = DMSetDS(*subdm, prob);CHKERRQ(ierr);
7412   /* Create map from submodel to global model */
7413   if (is) {
7414     PetscSection    sectionGlobal, subsectionGlobal;
7415     IS              spIS;
7416     const PetscInt *spmap;
7417     PetscInt       *subIndices;
7418     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
7419     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
7420 
7421     ierr = DMPlexCreateSubpointIS(*subdm, &spIS);CHKERRQ(ierr);
7422     ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr);
7423     ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
7424     ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
7425     ierr = DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr);
7426     ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr);
7427     for (p = pStart; p < pEnd; ++p) {
7428       PetscInt gdof, pSubSize  = 0;
7429 
7430       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
7431       if (gdof > 0) {
7432         for (f = 0; f < Nf; ++f) {
7433           PetscInt fdof, fcdof;
7434 
7435           ierr     = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr);
7436           ierr     = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr);
7437           pSubSize += fdof-fcdof;
7438         }
7439         subSize += pSubSize;
7440         if (pSubSize) {
7441           if (bs < 0) {
7442             bs = pSubSize;
7443           } else if (bs != pSubSize) {
7444             /* Layout does not admit a pointwise block size */
7445             bs = 1;
7446           }
7447         }
7448       }
7449     }
7450     /* Must have same blocksize on all procs (some might have no points) */
7451     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7452     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
7453     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7454     else                            {bs = bsMinMax[0];}
7455     ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr);
7456     for (p = pStart; p < pEnd; ++p) {
7457       PetscInt gdof, goff;
7458 
7459       ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr);
7460       if (gdof > 0) {
7461         const PetscInt point = spmap[p];
7462 
7463         ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr);
7464         for (f = 0; f < Nf; ++f) {
7465           PetscInt fdof, fcdof, fc, f2, poff = 0;
7466 
7467           /* Can get rid of this loop by storing field information in the global section */
7468           for (f2 = 0; f2 < f; ++f2) {
7469             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
7470             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
7471             poff += fdof-fcdof;
7472           }
7473           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7474           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7475           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7476             subIndices[subOff] = goff+poff+fc;
7477           }
7478         }
7479       }
7480     }
7481     ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr);
7482     ierr = ISDestroy(&spIS);CHKERRQ(ierr);
7483     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
7484     if (bs > 1) {
7485       /* We need to check that the block size does not come from non-contiguous fields */
7486       PetscInt i, j, set = 1;
7487       for (i = 0; i < subSize; i += bs) {
7488         for (j = 0; j < bs; ++j) {
7489           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7490         }
7491       }
7492       if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);}
7493     }
7494     /* Attach nullspace */
7495     for (f = 0; f < Nf; ++f) {
7496       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7497       if ((*subdm)->nullspaceConstructors[f]) break;
7498     }
7499     if (f < Nf) {
7500       MatNullSpace nullSpace;
7501 
7502       ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);CHKERRQ(ierr);
7503       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
7504       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
7505     }
7506   }
7507   PetscFunctionReturn(0);
7508 }
7509