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