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