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