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