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