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