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