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