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