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