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