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