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