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