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