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