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