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