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