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