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