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