Actual source code: plex.c

petsc-master 2017-04-20
Report Typos and Errors
  1:  #include <petsc/private/dmpleximpl.h>
  2:  #include <petsc/private/isimpl.h>
  3:  #include <petsc/private/vecimpl.h>
  4:  #include <petscsf.h>
  5:  #include <petscds.h>
  6:  #include <petscdraw.h>

  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;

 11: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

 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;

 19:   *ft  = PETSC_VTK_POINT_FIELD;
 20:   DMGetDimension(dm, &dim);
 21:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
 22:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
 23:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
 24:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
 25:   PetscSectionGetChart(section, &pStart, &pEnd);
 26:   if (field >= 0) {
 27:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vdof);}
 28:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &cdof);}
 29:   } else {
 30:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vdof);}
 31:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &cdof);}
 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:   return(0);
 45: }

 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;

 65:   PetscViewerDrawGetDraw(viewer, 0, &draw);
 66:   PetscDrawIsNull(draw, &isnull);
 67:   if (isnull) return(0);

 69:   VecGetDM(v, &dm);
 70:   DMGetCoordinateDim(dm, &dim);
 71:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
 72:   DMGetDefaultSection(dm, &s);
 73:   PetscSectionGetNumFields(s, &Nf);
 74:   DMGetCoarsenLevel(dm, &level);
 75:   DMGetCoordinateDM(dm, &cdm);
 76:   DMGetDefaultSection(cdm, &coordSection);
 77:   DMGetCoordinatesLocal(dm, &coordinates);
 78:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
 79:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

 81:   PetscObjectGetName((PetscObject) v, &name);
 82:   DMGetOutputSequenceNumber(dm, &step, &time);

 84:   VecGetLocalSize(coordinates, &N);
 85:   VecGetArrayRead(coordinates, &coords);
 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:   VecRestoreArrayRead(coordinates, &coords);
 91:   PetscDrawClear(draw);

 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;

101:     PetscSectionGetFieldComponents(s, f, &Nc);
102:     PetscSectionGetFieldName(s, f, &fname);

104:     if (v->hdr.prefix) {PetscStrcpy(prefix, v->hdr.prefix);}
105:     else               {prefix[0] = '\0';}
106:     if (Nf > 1) {
107:       DMCreateSubDM(dm, 1, &f, &fis, &fdm);
108:       VecGetSubVector(v, fis, &fv);
109:       PetscStrcat(prefix, fname);
110:       PetscStrcat(prefix, "_");
111:     }
112:     for (comp = 0; comp < Nc; ++comp, ++w) {
113:       PetscInt nmax = 2;

115:       PetscViewerDrawGetDraw(viewer, w, &draw);
116:       if (Nc > 1) {PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);}
117:       else        {PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);}
118:       PetscDrawSetTitle(draw, title);

120:       /* TODO Get max and min only for this component */
121:       PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
122:       if (!flg) {
123:         VecMin(fv, NULL, &vbound[0]);
124:         VecMax(fv, NULL, &vbound[1]);
125:         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
126:       }
127:       PetscDrawGetPopup(draw, &popup);
128:       PetscDrawScalePopup(popup, vbound[0], vbound[1]);
129:       PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);

131:       VecGetArrayRead(fv, &array);
132:       for (c = cStart; c < cEnd; ++c) {
133:         PetscScalar *coords = NULL, *a = NULL;
134:         PetscInt     numCoords, color[4];

136:         DMPlexPointLocalRead(fdm, c, array, &a);
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;

144:           DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
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:           DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
158:         }
159:         DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
160:         switch (numCoords) {
161:         case 6:
162:           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]);
163:           break;
164:         case 8:
165:           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]);
166:           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]);
167:           break;
168:         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
169:         }
170:         DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
171:       }
172:       VecRestoreArrayRead(fv, &array);
173:       PetscDrawFlush(draw);
174:       PetscDrawPause(draw);
175:       PetscDrawSave(draw);
176:     }
177:     if (Nf > 1) {
178:       VecRestoreSubVector(v, fis, &fv);
179:       ISDestroy(&fis);
180:       DMDestroy(&fdm);
181:     }
182:   }
183:   return(0);
184: }

186: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
187: {
188:   DM             dm;
189:   PetscBool      isvtk, ishdf5, isdraw, isseq;

193:   VecGetDM(v, &dm);
194:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
195:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
196:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
197:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
198:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
199:   if (isvtk || ishdf5) {
200:     PetscInt  numFields;
201:     PetscBool fem = PETSC_FALSE;

203:     DMGetNumFields(dm, &numFields);
204:     if (numFields) {
205:       PetscObject fe;

207:       DMGetField(dm, 0, &fe);
208:       if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE;
209:     }
210:     if (fem) {DMPlexInsertBoundaryValues(dm, PETSC_TRUE, v, 0.0, NULL, NULL, NULL);}
211:   }
212:   if (isvtk) {
213:     PetscSection            section;
214:     PetscViewerVTKFieldType ft;
215:     PetscInt                pStart, pEnd;

217:     DMGetDefaultSection(dm, &section);
218:     DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
219:     PetscObjectReference((PetscObject) v);  /* viewer drops reference */
220:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
221:   } else if (ishdf5) {
222: #if defined(PETSC_HAVE_HDF5)
223:     VecView_Plex_Local_HDF5_Internal(v, viewer);
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:     VecView_Plex_Local_Draw(v, viewer);
229:   } else {
230:     if (isseq) {VecView_Seq(v, viewer);}
231:     else       {VecView_MPI(v, viewer);}
232:   }
233:   return(0);
234: }

236: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
237: {
238:   DM             dm;
239:   PetscReal      time = 0.0;
240:   PetscBool      isvtk, ishdf5, isdraw, isseq;

244:   VecGetDM(v, &dm);
245:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
246:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
247:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
248:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
249:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
250:   if (isvtk) {
251:     Vec         locv;
252:     const char *name;

254:     DMGetLocalVector(dm, &locv);
255:     PetscObjectGetName((PetscObject) v, &name);
256:     PetscObjectSetName((PetscObject) locv, name);
257:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
258:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
259:     DMGetOutputSequenceNumber(dm, NULL, &time);
260:     DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
261:     VecView_Plex_Local(locv, viewer);
262:     DMRestoreLocalVector(dm, &locv);
263:   } else if (ishdf5) {
264: #if defined(PETSC_HAVE_HDF5)
265:     VecView_Plex_HDF5_Internal(v, viewer);
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;

273:     DMGetLocalVector(dm, &locv);
274:     PetscObjectGetName((PetscObject) v, &name);
275:     PetscObjectSetName((PetscObject) locv, name);
276:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
277:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
278:     DMGetOutputSequenceNumber(dm, NULL, &time);
279:     DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
280:     VecView_Plex_Local(locv, viewer);
281:     DMRestoreLocalVector(dm, &locv);
282:   } else {
283:     if (isseq) {VecView_Seq(v, viewer);}
284:     else       {VecView_MPI(v, viewer);}
285:   }
286:   return(0);
287: }

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;

299:   VecGetDM(originalv, &dm);
300:   PetscObjectGetComm((PetscObject) originalv, &comm);
301:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
302:   PetscViewerGetFormat(viewer, &format);
303:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
304:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
305:   if (format == PETSC_VIEWER_NATIVE) {
306:     const char *vecname;
307:     PetscInt    n, nroots;

309:     if (dm->sfNatural) {
310:       VecGetLocalSize(originalv, &n);
311:       PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
312:       if (n == nroots) {
313:         DMGetGlobalVector(dm, &v);
314:         DMPlexGlobalToNaturalBegin(dm, originalv, v);
315:         DMPlexGlobalToNaturalEnd(dm, originalv, v);
316:         PetscObjectGetName((PetscObject) originalv, &vecname);
317:         PetscObjectSetName((PetscObject) v, vecname);
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:     VecView_Plex_HDF5_Native_Internal(v, viewer);
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;

335:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
336:     if (isseq) {VecView_Seq(v, viewer);}
337:     else       {VecView_MPI(v, viewer);}
338:   }
339:   if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
340:   return(0);
341: }

343: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
344: {
345:   DM             dm;
346:   PetscBool      ishdf5;

350:   VecGetDM(v, &dm);
351:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
352:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
353:   if (ishdf5) {
354:     DM          dmBC;
355:     Vec         gv;
356:     const char *name;

358:     DMGetOutputDM(dm, &dmBC);
359:     DMGetGlobalVector(dmBC, &gv);
360:     PetscObjectGetName((PetscObject) v, &name);
361:     PetscObjectSetName((PetscObject) gv, name);
362:     VecLoad_Default(gv, viewer);
363:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
364:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
365:     DMRestoreGlobalVector(dmBC, &gv);
366:   } else {
367:     VecLoad_Default(v, viewer);
368:   }
369:   return(0);
370: }

372: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
373: {
374:   DM             dm;
375:   PetscBool      ishdf5;

379:   VecGetDM(v, &dm);
380:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
381:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
382:   if (ishdf5) {
383: #if defined(PETSC_HAVE_HDF5)
384:     VecLoad_Plex_HDF5_Internal(v, viewer);
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:     VecLoad_Default(v, viewer);
390:   }
391:   return(0);
392: }

394: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
395: {
396:   DM                dm;
397:   PetscViewerFormat format;
398:   PetscBool         ishdf5;
399:   PetscErrorCode    ierr;

402:   VecGetDM(originalv, &dm);
403:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
404:   PetscViewerGetFormat(viewer, &format);
405:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
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;

413:         DMGetGlobalVector(dm, &v);
414:         PetscObjectGetName((PetscObject) originalv, &vecname);
415:         PetscObjectSetName((PetscObject) v, vecname);
416:         VecLoad_Plex_HDF5_Native_Internal(v, viewer);
417:         DMPlexNaturalToGlobalBegin(dm, v, originalv);
418:         DMPlexNaturalToGlobalEnd(dm, v, originalv);
419:         DMRestoreGlobalVector(dm, &v);
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:   return(0);
427: }

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;

440:   DMGetDimension(dm, &dim);
441:   DMGetCoordinatesLocal(dm, &coordinates);
442:   DMGetCoordinateSection(dm, &coordSection);
443:   DMPlexGetDepthLabel(dm, &depthLabel);
444:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
445:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
446:   VecGetArrayRead(coordinates, &a);
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;

455:     PetscViewerASCIIPrintf(viewer, "Geometry for cell %D:\n", c);
456:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
457:     PetscViewerASCIIPushTab(viewer);
458:     for (cl = 0; cl < closureSize*2; cl += 2) {
459:       PetscInt point = closure[cl], depth, dof, off, d, p;

461:       if ((point < pStart) || (point >= pEnd)) continue;
462:       PetscSectionGetDof(coordSection, point, &dof);
463:       if (!dof) continue;
464:       DMLabelGetValue(depthLabel, point, &depth);
465:       PetscSectionGetOffset(coordSection, point, &off);
466:       PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
467:       for (p = 0; p < dof/dim; ++p) {
468:         PetscViewerASCIIPrintf(viewer, " (");
469:         for (d = 0; d < dim; ++d) {
470:           if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
471:           PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
472:         }
473:         PetscViewerASCIIPrintf(viewer, ")");
474:       }
475:       PetscViewerASCIIPrintf(viewer, "\n");
476:     }
477:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
478:     PetscViewerASCIIPopTab(viewer);
479:   }
480:   VecRestoreArrayRead(coordinates, &a);
481:   return(0);
482: }

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;

495:   DMGetCoordinateDM(dm, &cdm);
496:   DMGetDefaultSection(cdm, &coordSection);
497:   DMGetCoordinatesLocal(dm, &coordinates);
498:   PetscViewerGetFormat(viewer, &format);
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;

505:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
506:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
507:     PetscObjectGetName((PetscObject) dm, &name);
508:     DMPlexGetChart(dm, &pStart, &pEnd);
509:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
510:     PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);
511:     PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
512:     PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
513:     PetscViewerASCIIPushSynchronized(viewer);
514:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);
515:     for (p = pStart; p < pEnd; ++p) {
516:       PetscInt dof, off, s;

518:       PetscSectionGetDof(mesh->supportSection, p, &dof);
519:       PetscSectionGetOffset(mesh->supportSection, p, &off);
520:       for (s = off; s < off+dof; ++s) {
521:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
522:       }
523:     }
524:     PetscViewerFlush(viewer);
525:     PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
526:     for (p = pStart; p < pEnd; ++p) {
527:       PetscInt dof, off, c;

529:       PetscSectionGetDof(mesh->coneSection, p, &dof);
530:       PetscSectionGetOffset(mesh->coneSection, p, &off);
531:       for (c = off; c < off+dof; ++c) {
532:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
533:       }
534:     }
535:     PetscViewerFlush(viewer);
536:     PetscViewerASCIIPopSynchronized(viewer);
537:     PetscSectionGetChart(coordSection, &pStart, NULL);
538:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
539:     DMGetLabel(dm, "marker", &markers);
540:     DMLabelView(markers,viewer);
541:     if (size > 1) {
542:       PetscSF sf;

544:       DMGetPointSF(dm, &sf);
545:       PetscSFView(sf, viewer);
546:     }
547:     PetscViewerFlush(viewer);
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;

560:     DMGetDimension(dm, &dim);
561:     DMPlexGetDepth(dm, &depth);
562:     DMGetNumLabels(dm, &numLabels);
563:     numLabels  = PetscMax(numLabels, 10);
564:     numColors  = 10;
565:     numLColors = 10;
566:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
567:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
568:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
569:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
570:     if (!useLabels) numLabels = 0;
571:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
572:     if (!useColors) {
573:       numColors = 3;
574:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
575:     }
576:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
577:     if (!useColors) {
578:       numLColors = 4;
579:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
580:     }
581:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
582:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
583:     PetscObjectGetName((PetscObject) dm, &name);
584:     PetscViewerASCIIPrintf(viewer, "\
585: \\documentclass[tikz]{standalone}\n\n\
586: \\usepackage{pgflibraryshapes}\n\
587: \\usetikzlibrary{backgrounds}\n\
588: \\usetikzlibrary{arrows}\n\
589: \\begin{document}\n");
590:     if (size > 1) {
591:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
592:       for (p = 0; p < size; ++p) {
593:         if (p > 0 && p == size-1) {
594:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
595:         } else if (p > 0) {
596:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
597:         }
598:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
599:       }
600:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
601:     }
602:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);
603:     /* Plot vertices */
604:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
605:     VecGetArray(coordinates, &coords);
606:     PetscViewerASCIIPushSynchronized(viewer);
607:     for (v = vStart; v < vEnd; ++v) {
608:       PetscInt  off, dof, d;
609:       PetscBool isLabeled = PETSC_FALSE;

611:       PetscSectionGetDof(coordSection, v, &dof);
612:       PetscSectionGetOffset(coordSection, v, &off);
613:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
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) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
623:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
624:       }
625:       color = colors[rank%numColors];
626:       for (l = 0; l < numLabels; ++l) {
627:         PetscInt val;
628:         DMGetLabelValue(dm, names[l], v, &val);
629:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
630:       }
631:       if (useNumbers) {
632:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
633:       } else {
634:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
635:       }
636:     }
637:     VecRestoreArray(coordinates, &coords);
638:     PetscViewerFlush(viewer);
639:     /* Plot edges */
640:     if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
641:     if (dim < 3 && useNumbers) {
642:       VecGetArray(coordinates, &coords);
643:       PetscViewerASCIIPrintf(viewer, "\\path\n");
644:       for (e = eStart; e < eEnd; ++e) {
645:         const PetscInt *cone;
646:         PetscInt        coneSize, offA, offB, dof, d;

648:         DMPlexGetConeSize(dm, e, &coneSize);
649:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
650:         DMPlexGetCone(dm, e, &cone);
651:         PetscSectionGetDof(coordSection, cone[0], &dof);
652:         PetscSectionGetOffset(coordSection, cone[0], &offA);
653:         PetscSectionGetOffset(coordSection, cone[1], &offB);
654:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
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) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
663:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
664:         }
665:         color = colors[rank%numColors];
666:         for (l = 0; l < numLabels; ++l) {
667:           PetscInt val;
668:           DMGetLabelValue(dm, names[l], v, &val);
669:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
670:         }
671:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
672:       }
673:       VecRestoreArray(coordinates, &coords);
674:       PetscViewerFlush(viewer);
675:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
676:     }
677:     /* Plot cells */
678:     if (dim == 3 || !useNumbers) {
679:       for (e = eStart; e < eEnd; ++e) {
680:         const PetscInt *cone;

682:         color = colors[rank%numColors];
683:         for (l = 0; l < numLabels; ++l) {
684:           PetscInt val;
685:           DMGetLabelValue(dm, names[l], e, &val);
686:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
687:         }
688:         DMPlexGetCone(dm, e, &cone);
689:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
690:       }
691:     } else {
692:       DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
693:       for (c = cStart; c < cEnd; ++c) {
694:         PetscInt *closure = NULL;
695:         PetscInt  closureSize, firstPoint = -1;

697:         DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
698:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
699:         for (p = 0; p < closureSize*2; p += 2) {
700:           const PetscInt point = closure[p];

702:           if ((point < vStart) || (point >= vEnd)) continue;
703:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
704:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
705:           if (firstPoint < 0) firstPoint = point;
706:         }
707:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
708:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
709:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
710:       }
711:     }
712:     PetscViewerFlush(viewer);
713:     PetscViewerASCIIPopSynchronized(viewer);
714:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
715:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
716:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
717:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
718:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
719:     PetscFree3(names, colors, lcolors);
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;

729:     PetscObjectGetComm((PetscObject)dm,&comm);
730:     MPI_Comm_size(comm, &size);
731:     DMGetDimension(dm, &dim);
732:     PetscObjectGetName((PetscObject) dm, &name);
733:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);}
734:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);}
735:     DMPlexGetDepth(dm, &locDepth);
736:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
737:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);
738:     PetscMalloc2(size,&sizes,size,&hybsizes);
739:     if (depth == 1) {
740:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
741:       pEnd = pEnd - pStart;
742:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
743:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
744:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
745:       PetscViewerASCIIPrintf(viewer, "\n");
746:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
747:       pEnd = pEnd - pStart;
748:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
749:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
750:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
751:       PetscViewerASCIIPrintf(viewer, "\n");
752:     } else {
753:       PetscMPIInt rank;
754:       MPI_Comm_rank(comm, &rank);
755:       for (d = 0; d <= dim; d++) {
756:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
757:         pEnd    -= pStart;
758:         pMax[d] -= pStart;
759:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
760:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
761:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
762:         for (p = 0; p < size; ++p) {
763:           if (!rank) {
764:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
765:             else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
766:           }
767:         }
768:         PetscViewerASCIIPrintf(viewer, "\n");
769:       }
770:     }
771:     PetscFree2(sizes,hybsizes);
772:     DMGetNumLabels(dm, &numLabels);
773:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
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;

781:       DMGetLabelName(dm, l, &name);
782:       DMGetLabel(dm, name, &label);
783:       DMLabelGetNumValues(label, &numValues);
784:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata of sizes (", name, numValues);
785:       DMLabelGetValueIS(label, &valueIS);
786:       ISGetIndices(valueIS, &values);
787:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
788:       for (v = 0; v < numValues; ++v) {
789:         PetscInt size;

791:         DMLabelGetStratumSize(label, values[v], &size);
792:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
793:         PetscViewerASCIIPrintf(viewer, "%D", size);
794:       }
795:       PetscViewerASCIIPrintf(viewer, ")\n");
796:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
797:       ISRestoreIndices(valueIS, &values);
798:       ISDestroy(&valueIS);
799:     }
800:     DMGetCoarseDM(dm, &cdm);
801:     if (cdm) {
802:       PetscViewerASCIIPushTab(viewer);
803:       DMPlexView_Ascii(cdm, viewer);
804:       PetscViewerASCIIPopTab(viewer);
805:     }
806:   }
807:   return(0);
808: }

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;

823:   DMGetCoordinateDim(dm, &dim);
824:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
825:   DMGetCoordinateDM(dm, &cdm);
826:   DMGetDefaultSection(cdm, &coordSection);
827:   DMGetCoordinatesLocal(dm, &coordinates);
828:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
829:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

831:   PetscViewerDrawGetDraw(viewer, 0, &draw);
832:   PetscDrawIsNull(draw, &isnull);
833:   if (isnull) return(0);
834:   PetscDrawSetTitle(draw, "Mesh");

836:   VecGetLocalSize(coordinates, &N);
837:   VecGetArrayRead(coordinates, &coords);
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:   VecRestoreArrayRead(coordinates, &coords);
843:   PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
844:   PetscDrawClear(draw);

846:   for (c = cStart; c < cEnd; ++c) {
847:     PetscScalar *coords = NULL;
848:     PetscInt     numCoords;

850:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
851:     switch (numCoords) {
852:     case 6:
853:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
854:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
855:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
856:       break;
857:     case 8:
858:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
859:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
860:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
861:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
862:       break;
863:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
864:     }
865:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
866:   }
867:   PetscDrawFlush(draw);
868:   PetscDrawPause(draw);
869:   PetscDrawSave(draw);
870:   return(0);
871: }

873: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
874: {
875:   PetscBool      iascii, ishdf5, isvtk, isdraw;

881:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
882:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
883:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
884:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
885:   if (iascii) {
886:     DMPlexView_Ascii(dm, viewer);
887:   } else if (ishdf5) {
888: #if defined(PETSC_HAVE_HDF5)
889:     PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
890:     DMPlexView_HDF5_Internal(dm, viewer);
891:     PetscViewerPopFormat(viewer);
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:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
897:   } else if (isdraw) {
898:     DMPlexView_Draw(dm, viewer);
899:   }
900:   return(0);
901: }

903: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
904: {
905:   PetscBool      isbinary, ishdf5;

911:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
912:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
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:     DMPlexLoad_HDF5_Internal(dm, viewer);
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:   return(0);
922: }

924: PetscErrorCode DMDestroy_Plex(DM dm)
925: {
926:   DM_Plex       *mesh = (DM_Plex*) dm->data;

930:   if (--mesh->refct > 0) return(0);
931:   PetscSectionDestroy(&mesh->coneSection);
932:   PetscFree(mesh->cones);
933:   PetscFree(mesh->coneOrientations);
934:   PetscSectionDestroy(&mesh->supportSection);
935:   PetscSectionDestroy(&mesh->subdomainSection);
936:   PetscFree(mesh->supports);
937:   PetscFree(mesh->facesTmp);
938:   PetscFree(mesh->tetgenOpts);
939:   PetscFree(mesh->triangleOpts);
940:   PetscPartitionerDestroy(&mesh->partitioner);
941:   DMLabelDestroy(&mesh->subpointMap);
942:   ISDestroy(&mesh->globalVertexNumbers);
943:   ISDestroy(&mesh->globalCellNumbers);
944:   PetscSectionDestroy(&mesh->anchorSection);
945:   ISDestroy(&mesh->anchorIS);
946:   PetscSectionDestroy(&mesh->parentSection);
947:   PetscFree(mesh->parents);
948:   PetscFree(mesh->childIDs);
949:   PetscSectionDestroy(&mesh->childSection);
950:   PetscFree(mesh->children);
951:   DMDestroy(&mesh->referenceTree);
952:   PetscGridHashDestroy(&mesh->lbox);
953:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
954:   PetscFree(mesh);
955:   PetscObjectComposeFunction((PetscObject)dm,"DMAdaptLabel_C",NULL);
956:   return(0);
957: }

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;

970:   MatInitializePackage();
971:   mtype = dm->mattype;
972:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
973:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
974:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
975:   MatCreate(PetscObjectComm((PetscObject)dm), J);
976:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
977:   MatSetType(*J, mtype);
978:   MatSetFromOptions(*J);
979:   MatGetBlockSize(*J, &mbs);
980:   if (mbs > 1) bs = mbs;
981:   PetscStrcmp(mtype, MATSHELL, &isShell);
982:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
983:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
984:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
985:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
986:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
987:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
988:   PetscStrcmp(mtype, MATIS, &isMatIS);
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;

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;

1000:       DMGetDefaultSection(dm, &section);
1001:       PetscSectionGetStorageSize(section, &size);
1002:       PetscMalloc1(size,&ltogidx);
1003:       DMPlexGetSubdomainSection(dm, &subSection);
1004:     } else {
1005:       DMGetLocalToGlobalMapping(dm,&ltog);
1006:     }
1007:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1008:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1009:       PetscInt bdof;

1011:       PetscSectionGetDof(sectionGlobal, p, &dof);
1012:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
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:         PetscSectionGetOffset(subSection, p, &loff);
1022:         PetscSectionGetOffset(sectionGlobal, p, &off);
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:     MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1029:     bsLocal = bs < 0 ? bsMax : bs;
1030:     MPIU_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
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:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1039:     }
1040:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1041:     if (isMatIS) {
1042:       ISLocalToGlobalMappingDestroy(&ltog);
1043:     }
1044:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1045:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1046:     PetscFree4(dnz, onz, dnzu, onzu);
1047:   }
1048:   MatSetDM(*J, dm);
1049:   return(0);
1050: }

1052: /*@
1053:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1055:   Not collective

1057:   Input Parameter:
1058: . mesh - The DMPlex

1060:   Output Parameters:
1061: . subsection - The subdomain section

1063:   Level: developer

1065: .seealso:
1066: @*/
1067: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1068: {
1069:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1074:   if (!mesh->subdomainSection) {
1075:     PetscSection section;
1076:     PetscSF      sf;

1078:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1079:     DMGetDefaultSection(dm,&section);
1080:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1081:     PetscSFDestroy(&sf);
1082:   }
1083:   *subsection = mesh->subdomainSection;
1084:   return(0);
1085: }

1087: /*@
1088:   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)

1090:   Not collective

1092:   Input Parameter:
1093: . mesh - The DMPlex

1095:   Output Parameters:
1096: + pStart - The first mesh point
1097: - pEnd   - The upper bound for mesh points

1099:   Level: beginner

1101: .seealso: DMPlexCreate(), DMPlexSetChart()
1102: @*/
1103: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1104: {
1105:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1110:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1111:   return(0);
1112: }

1114: /*@
1115:   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)

1117:   Not collective

1119:   Input Parameters:
1120: + mesh - The DMPlex
1121: . pStart - The first mesh point
1122: - pEnd   - The upper bound for mesh points

1124:   Output Parameters:

1126:   Level: beginner

1128: .seealso: DMPlexCreate(), DMPlexGetChart()
1129: @*/
1130: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1131: {
1132:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1137:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1138:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1139:   return(0);
1140: }

1142: /*@
1143:   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG

1145:   Not collective

1147:   Input Parameters:
1148: + mesh - The DMPlex
1149: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1151:   Output Parameter:
1152: . size - The cone size for point p

1154:   Level: beginner

1156: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1157: @*/
1158: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1159: {
1160:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1166:   PetscSectionGetDof(mesh->coneSection, p, size);
1167:   return(0);
1168: }

1170: /*@
1171:   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG

1173:   Not collective

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

1180:   Output Parameter:

1182:   Note:
1183:   This should be called after DMPlexSetChart().

1185:   Level: beginner

1187: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1188: @*/
1189: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1190: {
1191:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1196:   PetscSectionSetDof(mesh->coneSection, p, size);

1198:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1199:   return(0);
1200: }

1202: /*@
1203:   DMPlexAddConeSize - Add the given number of in-edges to this point in the Sieve DAG

1205:   Not collective

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

1212:   Output Parameter:

1214:   Note:
1215:   This should be called after DMPlexSetChart().

1217:   Level: beginner

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;

1229:   PetscSectionAddDof(mesh->coneSection, p, size);
1230:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1232:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1233:   return(0);
1234: }

1236: /*@C
1237:   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG

1239:   Not collective

1241:   Input Parameters:
1242: + mesh - The DMPlex
1243: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1245:   Output Parameter:
1246: . cone - An array of points which are on the in-edges for point p

1248:   Level: beginner

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.

1254:   You must also call DMPlexRestoreCone() after you finish using the returned array.

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;

1267:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1268:   *cone = &mesh->cones[off];
1269:   return(0);
1270: }

1272: /*@
1273:   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG

1275:   Not collective

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

1282:   Output Parameter:

1284:   Note:
1285:   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().

1287:   Level: beginner

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;

1300:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1301:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1303:   PetscSectionGetOffset(mesh->coneSection, p, &off);
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:   return(0);
1310: }

1312: /*@C
1313:   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG

1315:   Not collective

1317:   Input Parameters:
1318: + mesh - The DMPlex
1319: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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.

1327:   Level: beginner

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.

1333:   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.

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;

1345: #if defined(PETSC_USE_DEBUG)
1346:   {
1347:     PetscInt dof;
1348:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1350:   }
1351: #endif
1352:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1354:   *coneOrientation = &mesh->coneOrientations[off];
1355:   return(0);
1356: }

1358: /*@
1359:   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG

1361:   Not collective

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.

1371:   Output Parameter:

1373:   Note:
1374:   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().

1376:   Level: beginner

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;

1389:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1390:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1392:   PetscSectionGetOffset(mesh->coneSection, p, &off);
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];

1397:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
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:   return(0);
1402: }

1404: /*@
1405:   DMPlexInsertCone - Insert a point into the in-edges for the point p in the Sieve DAG

1407:   Not collective

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

1415:   Level: beginner

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;

1428:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
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:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1432:   PetscSectionGetOffset(mesh->coneSection, p, &off);
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:   return(0);
1436: }

1438: /*@
1439:   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the Sieve DAG

1441:   Not collective

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

1449:   Level: beginner

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;

1462:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
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:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1465:   PetscSectionGetOffset(mesh->coneSection, p, &off);
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:   return(0);
1469: }

1471: /*@
1472:   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG

1474:   Not collective

1476:   Input Parameters:
1477: + mesh - The DMPlex
1478: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1480:   Output Parameter:
1481: . size - The support size for point p

1483:   Level: beginner

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;

1495:   PetscSectionGetDof(mesh->supportSection, p, size);
1496:   return(0);
1497: }

1499: /*@
1500:   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG

1502:   Not collective

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

1509:   Output Parameter:

1511:   Note:
1512:   This should be called after DMPlexSetChart().

1514:   Level: beginner

1516: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1517: @*/
1518: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1519: {
1520:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1525:   PetscSectionSetDof(mesh->supportSection, p, size);

1527:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1528:   return(0);
1529: }

1531: /*@C
1532:   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG

1534:   Not collective

1536:   Input Parameters:
1537: + mesh - The DMPlex
1538: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1540:   Output Parameter:
1541: . support - An array of points which are on the out-edges for point p

1543:   Level: beginner

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.

1549:   You must also call DMPlexRestoreSupport() after you finish using the returned array.

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;

1562:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1563:   *support = &mesh->supports[off];
1564:   return(0);
1565: }

1567: /*@
1568:   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG

1570:   Not collective

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

1577:   Output Parameter:

1579:   Note:
1580:   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().

1582:   Level: beginner

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;

1595:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1596:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1598:   PetscSectionGetOffset(mesh->supportSection, p, &off);
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:   return(0);
1605: }

1607: /*@
1608:   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the Sieve DAG

1610:   Not collective

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

1618:   Level: beginner

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;

1631:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1632:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1633:   PetscSectionGetOffset(mesh->supportSection, p, &off);
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:   return(0);
1639: }

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

1644:   Not collective

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

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, ...]

1656:   Note:
1657:   If using internal storage (points is NULL on input), each call overwrites the last output.

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.

1663:   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1665:   Level: beginner

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;

1681:   DMPlexGetDepth(dm, &depth);
1682:   /* This is only 1-level */
1683:   if (useCone) {
1684:     DMPlexGetConeSize(dm, p, &tmpSize);
1685:     DMPlexGetCone(dm, p, &tmp);
1686:     DMPlexGetConeOrientation(dm, p, &tmpO);
1687:   } else {
1688:     DMPlexGetSupportSize(dm, p, &tmpSize);
1689:     DMPlexGetSupport(dm, p, &tmp);
1690:   }
1691:   if (depth == 1) {
1692:     if (*points) {
1693:       closure = *points;
1694:     } else {
1695:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1696:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
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:     return(0);
1706:   }
1707:   {
1708:     PetscInt c, coneSeries, s,supportSeries;

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:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1717:   if (*points) {
1718:     closure = *points;
1719:   } else {
1720:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
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;

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;

1739:     if (useCone) {
1740:       DMPlexGetConeSize(dm, q, &tmpSize);
1741:       DMPlexGetCone(dm, q, &tmp);
1742:       DMPlexGetConeOrientation(dm, q, &tmpO);
1743:     } else {
1744:       DMPlexGetSupportSize(dm, q, &tmpSize);
1745:       DMPlexGetSupport(dm, q, &tmp);
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;

1757:       if (rev) {
1758:         PetscInt childSize, coff;
1759:         DMPlexGetConeSize(dm, cp, &childSize);
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:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1781:   return(0);
1782: }

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

1787:   Not collective

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

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, ...]

1800:   Note:
1801:   If using internal storage (points is NULL on input), each call overwrites the last output.

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.

1807:   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1809:   Level: beginner

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;

1825:   DMPlexGetDepth(dm, &depth);
1826:   /* This is only 1-level */
1827:   if (useCone) {
1828:     DMPlexGetConeSize(dm, p, &tmpSize);
1829:     DMPlexGetCone(dm, p, &tmp);
1830:     DMPlexGetConeOrientation(dm, p, &tmpO);
1831:   } else {
1832:     DMPlexGetSupportSize(dm, p, &tmpSize);
1833:     DMPlexGetSupport(dm, p, &tmp);
1834:   }
1835:   if (depth == 1) {
1836:     if (*points) {
1837:       closure = *points;
1838:     } else {
1839:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1840:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
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:     return(0);
1851:   }
1852:   {
1853:     PetscInt c, coneSeries, s,supportSeries;

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:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1862:   if (*points) {
1863:     closure = *points;
1864:   } else {
1865:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
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;

1873:     if (ornt < 0) {
1874:       PetscInt childSize, coff;
1875:       DMPlexGetConeSize(dm, cp, &childSize);
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;

1891:     if (useCone) {
1892:       DMPlexGetConeSize(dm, q, &tmpSize);
1893:       DMPlexGetCone(dm, q, &tmp);
1894:       DMPlexGetConeOrientation(dm, q, &tmpO);
1895:     } else {
1896:       DMPlexGetSupportSize(dm, q, &tmpSize);
1897:       DMPlexGetSupport(dm, q, &tmp);
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;

1909:       if (rev) {
1910:         PetscInt childSize, coff;
1911:         DMPlexGetConeSize(dm, cp, &childSize);
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:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1933:   return(0);
1934: }

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

1939:   Not collective

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

1948:   Note:
1949:   If not using internal storage (points is not NULL on input), this call is unnecessary

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.

1955:   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1957:   Level: beginner

1959: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1960: @*/
1961: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1962: {

1969:   DMRestoreWorkArray(dm, 0, PETSC_INT, points);
1970:   if (numPoints) *numPoints = 0;
1971:   return(0);
1972: }

1974: /*@
1975:   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG

1977:   Not collective

1979:   Input Parameter:
1980: . mesh - The DMPlex

1982:   Output Parameters:
1983: + maxConeSize - The maximum number of in-edges
1984: - maxSupportSize - The maximum number of out-edges

1986:   Level: beginner

1988: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1989: @*/
1990: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1991: {
1992:   DM_Plex *mesh = (DM_Plex*) dm->data;

1996:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1997:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1998:   return(0);
1999: }

2001: PetscErrorCode DMSetUp_Plex(DM dm)
2002: {
2003:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2004:   PetscInt       size;

2009:   PetscSectionSetUp(mesh->coneSection);
2010:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2011:   PetscMalloc1(size, &mesh->cones);
2012:   PetscCalloc1(size, &mesh->coneOrientations);
2013:   if (mesh->maxSupportSize) {
2014:     PetscSectionSetUp(mesh->supportSection);
2015:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2016:     PetscMalloc1(size, &mesh->supports);
2017:   }
2018:   return(0);
2019: }

2021: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
2022: {

2026:   if (subdm) {DMClone(dm, subdm);}
2027:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2028:   return(0);
2029: }

2031: /*@
2032:   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation

2034:   Not collective

2036:   Input Parameter:
2037: . mesh - The DMPlex

2039:   Output Parameter:

2041:   Note:
2042:   This should be called after all calls to DMPlexSetCone()

2044:   Level: beginner

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;

2058:   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2059:   /* Calculate support sizes */
2060:   DMPlexGetChart(dm, &pStart, &pEnd);
2061:   for (p = pStart; p < pEnd; ++p) {
2062:     PetscInt dof, off, c;

2064:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2065:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2066:     for (c = off; c < off+dof; ++c) {
2067:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2068:     }
2069:   }
2070:   for (p = pStart; p < pEnd; ++p) {
2071:     PetscInt dof;

2073:     PetscSectionGetDof(mesh->supportSection, p, &dof);

2075:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2076:   }
2077:   PetscSectionSetUp(mesh->supportSection);
2078:   /* Calculate supports */
2079:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2080:   PetscMalloc1(supportSize, &mesh->supports);
2081:   PetscCalloc1(pEnd - pStart, &offsets);
2082:   for (p = pStart; p < pEnd; ++p) {
2083:     PetscInt dof, off, c;

2085:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2086:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2087:     for (c = off; c < off+dof; ++c) {
2088:       const PetscInt q = mesh->cones[c];
2089:       PetscInt       offS;

2091:       PetscSectionGetOffset(mesh->supportSection, q, &offS);

2093:       mesh->supports[offS+offsets[q]] = p;
2094:       ++offsets[q];
2095:     }
2096:   }
2097:   PetscFree(offsets);
2098:   return(0);
2099: }

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.

2107:   Collective on dm

2109:   Input Parameter:
2110: . mesh - The DMPlex

2112:   Output Parameter:

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.

2120:   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()

2122:   Level: beginner

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;

2136:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2137:   /* Calculate depth */
2138:   DMPlexGetChart(dm, &pStart, &pEnd);
2139:   DMCreateLabel(dm, "depth");
2140:   DMPlexGetDepthLabel(dm, &label);
2141:   /* Initialize roots and count leaves */
2142:   for (p = pStart; p < pEnd; ++p) {
2143:     PetscInt coneSize, supportSize;

2145:     DMPlexGetConeSize(dm, p, &coneSize);
2146:     DMPlexGetSupportSize(dm, p, &supportSize);
2147:     if (!coneSize && supportSize) {
2148:       ++numRoots;
2149:       DMLabelSetValue(label, p, 0);
2150:     } else if (!supportSize && coneSize) {
2151:       ++numLeaves;
2152:     } else if (!supportSize && !coneSize) {
2153:       /* Isolated points */
2154:       DMLabelSetValue(label, p, 0);
2155:     }
2156:   }
2157:   if (numRoots + numLeaves == (pEnd - pStart)) {
2158:     for (p = pStart; p < pEnd; ++p) {
2159:       PetscInt coneSize, supportSize;

2161:       DMPlexGetConeSize(dm, p, &coneSize);
2162:       DMPlexGetSupportSize(dm, p, &supportSize);
2163:       if (!supportSize && coneSize) {
2164:         DMLabelSetValue(label, p, 1);
2165:       }
2166:     }
2167:   } else {
2168:     IS       pointIS;
2169:     PetscInt numPoints = 0, level = 0;

2171:     DMLabelGetStratumIS(label, level, &pointIS);
2172:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2173:     while (numPoints) {
2174:       const PetscInt *points;
2175:       const PetscInt  newLevel = level+1;

2177:       ISGetIndices(pointIS, &points);
2178:       for (p = 0; p < numPoints; ++p) {
2179:         const PetscInt  point = points[p];
2180:         const PetscInt *support;
2181:         PetscInt        supportSize, s;

2183:         DMPlexGetSupportSize(dm, point, &supportSize);
2184:         DMPlexGetSupport(dm, point, &support);
2185:         for (s = 0; s < supportSize; ++s) {
2186:           DMLabelSetValue(label, support[s], newLevel);
2187:         }
2188:       }
2189:       ISRestoreIndices(pointIS, &points);
2190:       ++level;
2191:       ISDestroy(&pointIS);
2192:       DMLabelGetStratumIS(label, level, &pointIS);
2193:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2194:       else         {numPoints = 0;}
2195:     }
2196:     ISDestroy(&pointIS);
2197:   }
2198:   { /* just in case there is an empty process */
2199:     PetscInt numValues, maxValues = 0, v;

2201:     DMLabelGetNumValues(label,&numValues);
2202:     for (v = 0; v < numValues; v++) {
2203:       IS pointIS;

2205:       DMLabelGetStratumIS(label, v, &pointIS);
2206:       if (pointIS) {
2207:         PetscInt  min, max, numPoints;
2208:         PetscInt  start;
2209:         PetscBool contig;

2211:         ISGetLocalSize(pointIS, &numPoints);
2212:         ISGetMinMax(pointIS, &min, &max);
2213:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2214:         if (start == 0 && contig) {
2215:           ISDestroy(&pointIS);
2216:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2217:           DMLabelSetStratumIS(label, v, pointIS);
2218:         }
2219:       }
2220:       ISDestroy(&pointIS);
2221:     }
2222:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2223:     for (v = numValues; v < maxValues; v++) {
2224:       DMLabelAddStratum(label,v);
2225:     }
2226:   }

2228:   DMLabelGetState(label, &mesh->depthState);
2229:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2230:   return(0);
2231: }

2233: /*@C
2234:   DMPlexGetJoin - Get an array for the join of the set of points

2236:   Not Collective

2238:   Input Parameters:
2239: + dm - The DMPlex object
2240: . numPoints - The number of input points for the join
2241: - points - The input points

2243:   Output Parameters:
2244: + numCoveredPoints - The number of points in the join
2245: - coveredPoints - The points in the join

2247:   Level: intermediate

2249:   Note: Currently, this is restricted to a single level join

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.

2255:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

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;

2273:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
2274:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
2275:   /* Copy in support of first point */
2276:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2277:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
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;

2285:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2286:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2287:     for (c = 0; c < dof; ++c) {
2288:       const PetscInt point = mesh->supports[off+c];

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:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2303:   return(0);
2304: }

2306: /*@C
2307:   DMPlexRestoreJoin - Restore an array for the join of the set of points

2309:   Not Collective

2311:   Input Parameters:
2312: + dm - The DMPlex object
2313: . numPoints - The number of input points for the join
2314: - points - The input points

2316:   Output Parameters:
2317: + numCoveredPoints - The number of points in the join
2318: - coveredPoints - The points in the join

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.

2324:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

2326:   Level: intermediate

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: {

2340:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2341:   if (numCoveredPoints) *numCoveredPoints = 0;
2342:   return(0);
2343: }

2345: /*@C
2346:   DMPlexGetFullJoin - Get an array for the join of the set of points

2348:   Not Collective

2350:   Input Parameters:
2351: + dm - The DMPlex object
2352: . numPoints - The number of input points for the join
2353: - points - The input points

2355:   Output Parameters:
2356: + numCoveredPoints - The number of points in the join
2357: - coveredPoints - The points in the join

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.

2363:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

2365:   Level: intermediate

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;


2385:   DMPlexGetDepth(dm, &depth);
2386:   PetscCalloc1(numPoints, &closures);
2387:   DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2388:   ms      = mesh->maxSupportSize;
2389:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2390:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
2391:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);

2393:   for (p = 0; p < numPoints; ++p) {
2394:     PetscInt closureSize;

2396:     DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);

2398:     offsets[p*(depth+2)+0] = 0;
2399:     for (d = 0; d < depth+1; ++d) {
2400:       PetscInt pStart, pEnd, i;

2402:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
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;

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;

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];

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:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2445:   }
2446:   PetscFree(closures);
2447:   DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2448:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2449:   return(0);
2450: }

2452: /*@C
2453:   DMPlexGetMeet - Get an array for the meet of the set of points

2455:   Not Collective

2457:   Input Parameters:
2458: + dm - The DMPlex object
2459: . numPoints - The number of input points for the meet
2460: - points - The input points

2462:   Output Parameters:
2463: + numCoveredPoints - The number of points in the meet
2464: - coveredPoints - The points in the meet

2466:   Level: intermediate

2468:   Note: Currently, this is restricted to a single level meet

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.

2474:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

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;

2492:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
2493:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
2494:   /* Copy in cone of first point */
2495:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2496:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
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;

2504:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2505:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2506:     for (c = 0; c < dof; ++c) {
2507:       const PetscInt point = mesh->cones[off+c];

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:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2522:   return(0);
2523: }

2525: /*@C
2526:   DMPlexRestoreMeet - Restore an array for the meet of the set of points

2528:   Not Collective

2530:   Input Parameters:
2531: + dm - The DMPlex object
2532: . numPoints - The number of input points for the meet
2533: - points - The input points

2535:   Output Parameters:
2536: + numCoveredPoints - The number of points in the meet
2537: - coveredPoints - The points in the meet

2539:   Level: intermediate

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.

2545:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

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: {

2559:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2560:   if (numCoveredPoints) *numCoveredPoints = 0;
2561:   return(0);
2562: }

2564: /*@C
2565:   DMPlexGetFullMeet - Get an array for the meet of the set of points

2567:   Not Collective

2569:   Input Parameters:
2570: + dm - The DMPlex object
2571: . numPoints - The number of input points for the meet
2572: - points - The input points

2574:   Output Parameters:
2575: + numCoveredPoints - The number of points in the meet
2576: - coveredPoints - The points in the meet

2578:   Level: intermediate

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.

2584:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

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;


2604:   DMPlexGetDepth(dm, &height);
2605:   PetscMalloc1(numPoints, &closures);
2606:   DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2607:   mc      = mesh->maxConeSize;
2608:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2609:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
2610:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);

2612:   for (p = 0; p < numPoints; ++p) {
2613:     PetscInt closureSize;

2615:     DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);

2617:     offsets[p*(height+2)+0] = 0;
2618:     for (h = 0; h < height+1; ++h) {
2619:       PetscInt pStart, pEnd, i;

2621:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
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;

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;

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];

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:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2664:   }
2665:   PetscFree(closures);
2666:   DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2667:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2668:   return(0);
2669: }

2671: /*@C
2672:   DMPlexEqual - Determine if two DMs have the same topology

2674:   Not Collective

2676:   Input Parameters:
2677: + dmA - A DMPlex object
2678: - dmB - A DMPlex object

2680:   Output Parameters:
2681: . equal - PETSC_TRUE if the topologies are identical

2683:   Level: intermediate

2685:   Notes:
2686:   We are not solving graph isomorphism, so we do not permutation.

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;


2701:   *equal = PETSC_FALSE;
2702:   DMPlexGetDepth(dmA, &depth);
2703:   DMPlexGetDepth(dmB, &depthB);
2704:   if (depth != depthB) return(0);
2705:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2706:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2707:   if ((pStart != pStartB) || (pEnd != pEndB)) return(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;

2712:     DMPlexGetConeSize(dmA, p, &coneSize);
2713:     DMPlexGetCone(dmA, p, &cone);
2714:     DMPlexGetConeOrientation(dmA, p, &ornt);
2715:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2716:     DMPlexGetCone(dmB, p, &coneB);
2717:     DMPlexGetConeOrientation(dmB, p, &orntB);
2718:     if (coneSize != coneSizeB) return(0);
2719:     for (c = 0; c < coneSize; ++c) {
2720:       if (cone[c] != coneB[c]) return(0);
2721:       if (ornt[c] != orntB[c]) return(0);
2722:     }
2723:     DMPlexGetSupportSize(dmA, p, &supportSize);
2724:     DMPlexGetSupport(dmA, p, &support);
2725:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2726:     DMPlexGetSupport(dmB, p, &supportB);
2727:     if (supportSize != supportSizeB) return(0);
2728:     for (s = 0; s < supportSize; ++s) {
2729:       if (support[s] != supportB[s]) return(0);
2730:     }
2731:   }
2732:   *equal = PETSC_TRUE;
2733:   return(0);
2734: }

2736: /*@C
2737:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

2739:   Not Collective

2741:   Input Parameters:
2742: + dm         - The DMPlex
2743: . cellDim    - The cell dimension
2744: - numCorners - The number of vertices on a cell

2746:   Output Parameters:
2747: . numFaceVertices - The number of vertices on a face

2749:   Level: developer

2751:   Notes:
2752:   Of course this can only work for a restricted set of symmetric shapes

2754: .seealso: DMPlexGetCone()
2755: @*/
2756: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2757: {
2758:   MPI_Comm       comm;

2762:   PetscObjectGetComm((PetscObject)dm,&comm);
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:   return(0);
2823: }

2825: /*@
2826:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

2828:   Not Collective

2830:   Input Parameter:
2831: . dm    - The DMPlex object

2833:   Output Parameter:
2834: . depthLabel - The DMLabel recording point depth

2836:   Level: developer

2838: .keywords: mesh, points
2839: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2840: @*/
2841: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2842: {

2848:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
2849:   *depthLabel = dm->depthLabel;
2850:   return(0);
2851: }

2853: /*@
2854:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

2856:   Not Collective

2858:   Input Parameter:
2859: . dm    - The DMPlex object

2861:   Output Parameter:
2862: . depth - The number of strata (breadth first levels) in the DAG

2864:   Level: developer

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;

2878:   DMPlexGetDepthLabel(dm, &label);
2879:   if (label) {DMLabelGetNumValues(label, &d);}
2880:   *depth = d-1;
2881:   return(0);
2882: }

2884: /*@
2885:   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.

2887:   Not Collective

2889:   Input Parameters:
2890: + dm           - The DMPlex object
2891: - stratumValue - The requested depth

2893:   Output Parameters:
2894: + start - The first point at this depth
2895: - end   - One beyond the last point at this depth

2897:   Level: developer

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;

2912:   DMPlexGetChart(dm, &pStart, &pEnd);
2913:   if (pStart == pEnd) return(0);
2914:   if (stratumValue < 0) {
2915:     if (start) *start = pStart;
2916:     if (end)   *end   = pEnd;
2917:     return(0);
2918:   }
2919:   DMPlexGetDepthLabel(dm, &label);
2920:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2921:   DMLabelGetStratumBounds(label, stratumValue, start, end);
2922:   return(0);
2923: }

2925: /*@
2926:   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.

2928:   Not Collective

2930:   Input Parameters:
2931: + dm           - The DMPlex object
2932: - stratumValue - The requested height

2934:   Output Parameters:
2935: + start - The first point at this height
2936: - end   - One beyond the last point at this height

2938:   Level: developer

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;

2953:   DMPlexGetChart(dm, &pStart, &pEnd);
2954:   if (pStart == pEnd) return(0);
2955:   if (stratumValue < 0) {
2956:     if (start) *start = pStart;
2957:     if (end)   *end   = pEnd;
2958:     return(0);
2959:   }
2960:   DMPlexGetDepthLabel(dm, &label);
2961:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2962:   DMLabelGetNumValues(label, &depth);
2963:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
2964:   return(0);
2965: }

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;

2977:   PetscMalloc1(numFields, &isFE);
2978:   DMGetNumFields(dm, &Nf);
2979:   for (f = 0; f < numFields; ++f) {
2980:     PetscObject  obj;
2981:     PetscClassId id;

2983:     isFE[f] = PETSC_FALSE;
2984:     if (f >= Nf) continue;
2985:     DMGetField(dm, f, &obj);
2986:     PetscObjectGetClassId(obj, &id);
2987:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
2988:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2989:   }
2990:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
2991:   if (numFields > 0) {
2992:     PetscSectionSetNumFields(*section, numFields);
2993:     if (numComp) {
2994:       for (f = 0; f < numFields; ++f) {
2995:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
2996:         if (isFE[f]) {
2997:           PetscFE           fe;
2998:           PetscDualSpace    dspace;
2999:           const PetscInt    ***perms;
3000:           const PetscScalar ***flips;
3001:           const PetscInt    *numDof;

3003:           DMGetField(dm,f,(PetscObject *) &fe);
3004:           PetscFEGetDualSpace(fe,&dspace);
3005:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3006:           PetscDualSpaceGetNumDof(dspace,&numDof);
3007:           if (perms || flips) {
3008:             DM               K;
3009:             DMLabel          depthLabel;
3010:             PetscInt         depth, h;
3011:             PetscSectionSym  sym;

3013:             PetscDualSpaceGetDM(dspace,&K);
3014:             DMPlexGetDepthLabel(dm,&depthLabel);
3015:             DMPlexGetDepth(dm,&depth);
3016:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
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;

3024:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
3025:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
3026:               if (!hspace) continue;
3027:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
3028:               if (perms) perms0 = perms[0];
3029:               if (flips) flips0 = flips[0];
3030:               if (!(perms0 || flips0)) continue;
3031:               DMPlexGetConeSize(K,kStart,&kConeSize);
3032:               if (numComp[f] == 1) {
3033:                 PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
3034:               } else {
3035:                 PetscInt    **fieldPerms = NULL, o;
3036:                 PetscScalar **fieldFlips = NULL;

3038:                 PetscCalloc1(2 * kConeSize,&fieldPerms);
3039:                 PetscCalloc1(2 * kConeSize,&fieldFlips);
3040:                 for (o = -kConeSize; o < kConeSize; o++) {
3041:                   if (perms0 && perms0[o]) {
3042:                     PetscInt r, s;

3044:                     PetscMalloc1(numComp[f] * numDof[depth - h],&fieldPerms[o+kConeSize]);
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;

3054:                     PetscMalloc1(numComp[f] * numDof[depth - h],&fieldFlips[o+kConeSize]);
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:                 PetscSectionSymLabelSetStratum(sym,depth - h,numComp[f] * numDof[depth - h],-kConeSize,kConeSize,PETSC_OWN_POINTER,(const PetscInt **) fieldPerms,(const PetscScalar **)fieldFlips);
3063:               }
3064:             }
3065:             PetscSectionSetFieldSym(*section,f,sym);
3066:             PetscSectionSymDestroy(&sym);
3067:           }
3068:         }
3069:       }
3070:     }
3071:   }
3072:   DMPlexGetChart(dm, &pStart, &pEnd);
3073:   PetscSectionSetChart(*section, pStart, pEnd);
3074:   DMPlexGetDepth(dm, &depth);
3075:   PetscMalloc1(depth+1,&pMax);
3076:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3077:   for (dep = 0; dep <= depth; ++dep) {
3078:     d    = dim == depth ? dep : (!dep ? 0 : dim);
3079:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3080:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3081:     for (p = pStart; p < pEnd; ++p) {
3082:       PetscInt tot = 0;

3084:       for (f = 0; f < numFields; ++f) {
3085:         if (isFE[f] && p >= pMax[dep]) continue;
3086:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3087:         tot += numDof[f*(dim+1)+d];
3088:       }
3089:       PetscSectionSetDof(*section, p, tot);
3090:     }
3091:   }
3092:   PetscFree(pMax);
3093:   PetscFree(isFE);
3094:   return(0);
3095: }

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;

3108:   PetscSectionGetNumFields(section, &numFields);
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;

3115:     if (numFields) field = bcField[bc];
3116:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3117:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3118:     ISGetLocalSize(bcPoints[bc], &n);
3119:     ISGetIndices(bcPoints[bc], &idx);
3120:     for (i = 0; i < n; ++i) {
3121:       const PetscInt p = idx[i];
3122:       PetscInt       numConst;

3124:       if (numFields) {
3125:         PetscSectionGetFieldDof(section, p, field, &numConst);
3126:       } else {
3127:         PetscSectionGetDof(section, p, &numConst);
3128:       }
3129:       /* If Nc < 0, constrain every dof on the point */
3130:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3131:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3132:       PetscSectionAddConstraintDof(section, p, numConst);
3133:     }
3134:     ISRestoreIndices(bcPoints[bc], &idx);
3135:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3136:   }
3137:   DMPlexGetAnchors(dm, &aSec, NULL);
3138:   if (aSec) {
3139:     PetscInt aStart, aEnd, a;

3141:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3142:     for (a = aStart; a < aEnd; a++) {
3143:       PetscInt dof, f;

3145:       PetscSectionGetDof(aSec, a, &dof);
3146:       if (dof) {
3147:         /* if there are point-to-point constraints, then all dofs are constrained */
3148:         PetscSectionGetDof(section, a, &dof);
3149:         PetscSectionSetConstraintDof(section, a, dof);
3150:         for (f = 0; f < numFields; f++) {
3151:           PetscSectionGetFieldDof(section, a, f, &dof);
3152:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3153:         }
3154:       }
3155:     }
3156:   }
3157:   return(0);
3158: }

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;

3171:   PetscSectionGetNumFields(section, &numFields);
3172:   if (!numFields) return(0);
3173:   /* Initialize all field indices to -1 */
3174:   PetscSectionGetChart(section, &pStart, &pEnd);
3175:   PetscSectionGetMaxDof(section, &maxDof);
3176:   PetscMalloc1(maxDof, &indices);
3177:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3178:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
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;

3185:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3186:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3187:     ISGetLocalSize(bcPoints[bc], &n);
3188:     ISGetIndices(bcPoints[bc], &idx);
3189:     for (i = 0; i < n; ++i) {
3190:       const PetscInt  p = idx[i];
3191:       const PetscInt *find;
3192:       PetscInt        fcdof, c;

3194:       PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3195:       if (Nc < 0) {
3196:         for (d = 0; d < fcdof; ++d) indices[d] = d;
3197:       } else {
3198:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
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:         PetscSortInt(d+Nc, indices);
3202:         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
3203:       }
3204:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3205:     }
3206:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3207:     ISRestoreIndices(bcPoints[bc], &idx);
3208:   }
3209:   /* Handle anchors */
3210:   DMPlexGetAnchors(dm, &aSec, NULL);
3211:   if (aSec) {
3212:     PetscInt aStart, aEnd, a;

3214:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3215:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3216:     for (a = aStart; a < aEnd; a++) {
3217:       PetscInt dof, fdof, f;

3219:       PetscSectionGetDof(aSec, a, &dof);
3220:       if (dof) {
3221:         /* if there are point-to-point constraints, then all dofs are constrained */
3222:         for (f = 0; f < numFields; f++) {
3223:           PetscSectionGetFieldDof(section, a, f, &fdof);
3224:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3225:         }
3226:       }
3227:     }
3228:   }
3229:   PetscFree(indices);
3230:   return(0);
3231: }

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;

3241:   PetscSectionGetNumFields(section, &numFields);
3242:   PetscSectionGetMaxDof(section, &maxDof);
3243:   PetscSectionGetChart(section, &pStart, &pEnd);
3244:   PetscMalloc1(maxDof, &indices);
3245:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3246:   for (p = pStart; p < pEnd; ++p) {
3247:     PetscInt cdof, d;

3249:     PetscSectionGetConstraintDof(section, p, &cdof);
3250:     if (cdof) {
3251:       if (numFields) {
3252:         PetscInt numConst = 0, foff = 0;

3254:         for (f = 0; f < numFields; ++f) {
3255:           const PetscInt *find;
3256:           PetscInt        fcdof, fdof;

3258:           PetscSectionGetFieldDof(section, p, f, &fdof);
3259:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3260:           /* Change constraint numbering from field component to local dof number */
3261:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
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:       PetscSectionSetConstraintIndices(section, p, indices);
3271:     }
3272:   }
3273:   PetscFree(indices);
3274:   return(0);
3275: }

3277: /*@C
3278:   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.

3280:   Not Collective

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

3294:   Output Parameter:
3295: . section - The PetscSection object

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.

3300:   The chart permutation is the same one set using PetscSectionSetPermutation()

3302:   Level: developer

3304:   Fortran Notes:
3305:   A Fortran 90 version is available as DMPlexCreateSectionF90()

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;

3316:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3317:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3318:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3319:   PetscSectionSetUp(*section);
3320:   DMPlexGetAnchors(dm,&aSec,NULL);
3321:   if (numBC || aSec) {
3322:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3323:     DMPlexCreateSectionBCIndices(dm, *section);
3324:   }
3325:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3326:   return(0);
3327: }

3329: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3330: {
3331:   PetscSection   section, s;
3332:   Mat            m;
3333:   PetscInt       maxHeight;

3337:   DMClone(dm, cdm);
3338:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3339:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3340:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3341:   DMSetDefaultSection(*cdm, section);
3342:   PetscSectionDestroy(&section);
3343:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3344:   MatCreate(PETSC_COMM_SELF, &m);
3345:   DMSetDefaultConstraints(*cdm, s, m);
3346:   PetscSectionDestroy(&s);
3347:   MatDestroy(&m);
3348:   return(0);
3349: }

3351: /*@C
3352:   DMPlexGetConeSection - Return a section which describes the layout of cone data

3354:   Not Collective

3356:   Input Parameters:
3357: . dm        - The DMPlex object

3359:   Output Parameter:
3360: . section - The PetscSection object

3362:   Level: developer

3364: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3365: @*/
3366: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3367: {
3368:   DM_Plex *mesh = (DM_Plex*) dm->data;

3372:   if (section) *section = mesh->coneSection;
3373:   return(0);
3374: }

3376: /*@C
3377:   DMPlexGetSupportSection - Return a section which describes the layout of support data

3379:   Not Collective

3381:   Input Parameters:
3382: . dm        - The DMPlex object

3384:   Output Parameter:
3385: . section - The PetscSection object

3387:   Level: developer

3389: .seealso: DMPlexGetConeSection()
3390: @*/
3391: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3392: {
3393:   DM_Plex *mesh = (DM_Plex*) dm->data;

3397:   if (section) *section = mesh->supportSection;
3398:   return(0);
3399: }

3401: /*@C
3402:   DMPlexGetCones - Return cone data

3404:   Not Collective

3406:   Input Parameters:
3407: . dm        - The DMPlex object

3409:   Output Parameter:
3410: . cones - The cone for each point

3412:   Level: developer

3414: .seealso: DMPlexGetConeSection()
3415: @*/
3416: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3417: {
3418:   DM_Plex *mesh = (DM_Plex*) dm->data;

3422:   if (cones) *cones = mesh->cones;
3423:   return(0);
3424: }

3426: /*@C
3427:   DMPlexGetConeOrientations - Return cone orientation data

3429:   Not Collective

3431:   Input Parameters:
3432: . dm        - The DMPlex object

3434:   Output Parameter:
3435: . coneOrientations - The cone orientation for each point

3437:   Level: developer

3439: .seealso: DMPlexGetConeSection()
3440: @*/
3441: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3442: {
3443:   DM_Plex *mesh = (DM_Plex*) dm->data;

3447:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3448:   return(0);
3449: }

3451: /******************************** FEM Support **********************************/

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;

3460:   if (!section) {DMGetDefaultSection(dm, &section);}
3461:   DMGetDimension(dm, &dim);
3462:   PetscSectionGetNumFields(section, &Nf);
3463:   if (dim <= 1) return(0);
3464:   for (f = 0; f < Nf; ++f) {
3465:     /* An order k SEM disc has k-1 dofs on an edge */
3466:     DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3467:     PetscSectionGetFieldDof(section, eStart, f, &k);
3468:     PetscSectionGetFieldComponents(section, f, &Nc);
3469:     k = k/Nc + 1;
3470:     size += PetscPowInt(k+1, dim)*Nc;
3471:   }
3472:   PetscMalloc1(size, &perm);
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:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3478:       PetscSectionGetFieldDof(section, eStart, f, &k);
3479:       PetscSectionGetFieldComponents(section, f, &Nc);
3480:       k = k/Nc + 1;
3481:       /* The SEM order is

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;

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

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:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3525:       PetscSectionGetFieldDof(section, eStart, f, &k);
3526:       PetscSectionGetFieldComponents(section, f, &Nc);
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,

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,

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;

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;

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:         }

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;

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;

3635:     PetscMalloc1(size, &check);
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:     PetscFree(check);
3640:   }
3641:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3642:   return(0);
3643: }

3645: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3646: {
3647:   PetscDS        prob;
3648:   PetscInt       depth, Nf, h;
3649:   DMLabel        label;

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];

3660:     if (disc->classid == PETSCFE_CLASSID) {
3661:       PetscDualSpace dsp;

3663:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3664:       DMLabelGetNumValues(label,&depth);
3665:       DMLabelGetValue(label,point,&h);
3666:       h    = depth - 1 - h;
3667:       if (h) {
3668:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3669:       } else {
3670:         *dspace = dsp;
3671:       }
3672:     }
3673:   }
3674:   return(0);
3675: }


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;

3686:   PetscSectionGetChart(section, &pStart, &pEnd);
3687:   DMPlexGetConeSize(dm, point, &numPoints);
3688:   DMPlexGetCone(dm, point, &cone);
3689:   DMPlexGetConeOrientation(dm, point, &coneO);
3690:   if (!values || !*values) {
3691:     if ((point >= pStart) && (point < pEnd)) {
3692:       PetscInt dof;

3694:       PetscSectionGetDof(section, point, &dof);
3695:       size += dof;
3696:     }
3697:     for (p = 0; p < numPoints; ++p) {
3698:       const PetscInt cp = cone[p];
3699:       PetscInt       dof;

3701:       if ((cp < pStart) || (cp >= pEnd)) continue;
3702:       PetscSectionGetDof(section, cp, &dof);
3703:       size += dof;
3704:     }
3705:     if (!values) {
3706:       if (csize) *csize = size;
3707:       return(0);
3708:     }
3709:     DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
3710:   } else {
3711:     array = *values;
3712:   }
3713:   size = 0;
3714:   VecGetArray(v, &vArray);
3715:   if ((point >= pStart) && (point < pEnd)) {
3716:     PetscInt     dof, off, d;
3717:     PetscScalar *varr;

3719:     PetscSectionGetDof(section, point, &dof);
3720:     PetscSectionGetOffset(section, point, &off);
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;

3733:     if ((cp < pStart) || (cp >= pEnd)) continue;
3734:     PetscSectionGetDof(section, cp, &dof);
3735:     PetscSectionGetOffset(section, cp, &off);
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:   VecRestoreArray(v, &vArray);
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:   return(0);
3757: }

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;

3766:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3767:   if (!*clPoints) {
3768:     PetscInt pStart, pEnd, p, q;

3770:     PetscSectionGetChart(section, &pStart, &pEnd);
3771:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
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;

3786:     PetscSectionGetDof(*clSec, point, &dof);
3787:     PetscSectionGetOffset(*clSec, point, &off);
3788:     ISGetIndices(*clPoints, &cla);
3789:     np   = dof/2;
3790:     pts  = (PetscInt *) &cla[off];
3791:   }
3792:   *numPoints = np;
3793:   *points    = pts;
3794:   *clp       = cla;

3796:   return(0);
3797: }

3799: static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3800: {

3804:   if (!*clPoints) {
3805:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3806:   } else {
3807:     ISRestoreIndices(*clPoints, clp);
3808:   }
3809:   *numPoints = 0;
3810:   *points    = NULL;
3811:   *clSec     = NULL;
3812:   *clPoints  = NULL;
3813:   *clp       = NULL;
3814:   return(0);
3815: }

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;

3825:   *size = 0;
3826:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
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;

3834:     PetscSectionGetDof(section, point, &dof);
3835:     PetscSectionGetOffset(section, point, &off);
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:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3859:   *size = offset;
3860:   return(0);
3861: }

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;

3869:   *size = 0;
3870:   for (f = 0; f < numFields; ++f) {
3871:     PetscInt          p;
3872:     const PetscInt    **perms = NULL;
3873:     const PetscScalar **flips = NULL;

3875:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
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;

3883:       PetscSectionGetFieldDof(section, point, f, &fdof);
3884:       PetscSectionGetFieldOffset(section, point, f, &foff);
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:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3898:   }
3899:   *size = offset;
3900:   return(0);
3901: }

3903: /*@C
3904:   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'

3906:   Not collective

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

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

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.

3922:   The csize argument is not present in the Fortran 90 binding since it is internal to the array.

3924:   Level: intermediate

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;

3941:   if (!section) {DMGetDefaultSection(dm, &section);}
3944:   DMPlexGetDepth(dm, &depth);
3945:   PetscSectionGetNumFields(section, &numFields);
3946:   if (depth == 1 && numFields < 2) {
3947:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
3948:     return(0);
3949:   }
3950:   /* Get points */
3951:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3952:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
3953:   /* Get array */
3954:   if (!values || !*values) {
3955:     PetscInt asize = 0, dof, p;

3957:     for (p = 0; p < numPoints*2; p += 2) {
3958:       PetscSectionGetDof(section, points[p], &dof);
3959:       asize += dof;
3960:     }
3961:     if (!values) {
3962:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3963:       if (csize) *csize = asize;
3964:       return(0);
3965:     }
3966:     DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
3967:   } else {
3968:     array = *values;
3969:   }
3970:   VecGetArrayRead(v, &vArray);
3971:   /* Get values */
3972:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
3973:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
3974:   /* Cleanup points */
3975:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3976:   /* Cleanup array */
3977:   VecRestoreArrayRead(v, &vArray);
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:   return(0);
3986: }

3988: /*@C
3989:   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'

3991:   Not collective

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

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.

4005:   The csize argument is not present in the Fortran 90 binding since it is internal to the array.

4007:   Level: intermediate

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;

4017:   /* Should work without recalculating size */
4018:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
4019:   return(0);
4020: }

4022: PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
4023: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}

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;

4034:   PetscSectionGetConstraintDof(section, point, &cdof);
4035:   PetscSectionGetOffset(section, point, &off);
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:     PetscSectionGetConstraintIndices(section, point, &cdofs);
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:   return(0);
4073: }

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;

4084:   PetscSectionGetConstraintDof(section, point, &cdof);
4085:   PetscSectionGetOffset(section, point, &off);
4086:   a    = &array[off];
4087:   if (cdof) {
4088:     PetscSectionGetConstraintIndices(section, point, &cdofs);
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:   return(0);
4124: }

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;

4135:   PetscSectionGetFieldDof(section, point, f, &fdof);
4136:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4137:   PetscSectionGetFieldOffset(section, point, f, &foff);
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:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
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:   return(0);
4177: }

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;

4188:   PetscSectionGetFieldDof(section, point, f, &fdof);
4189:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4190:   PetscSectionGetFieldOffset(section, point, f, &foff);
4191:   a    = &array[foff];
4192:   if (fcdof) {
4193:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
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:   return(0);
4230: }

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;

4240:   PetscSectionGetChart(section, &pStart, &pEnd);
4241:   DMPlexGetConeSize(dm, point, &numPoints);
4242:   DMPlexGetCone(dm, point, &cone);
4243:   DMPlexGetConeOrientation(dm, point, &coneO);
4244:   VecGetArray(v, &array);
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];

4249:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4250:     PetscSectionGetDof(section, cp, &dof);
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;

4257:       PetscSectionGetConstraintDof(section, cp, &cdof);
4258:       PetscSectionGetOffset(section, cp, &coff);
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:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
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:   VecRestoreArray(v, &array);
4287:   return(0);
4288: }

4290: /*@C
4291:   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'

4293:   Not collective

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

4303:   Fortran Notes:
4304:   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.

4306:   Level: intermediate

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;

4322:   if (!section) {DMGetDefaultSection(dm, &section);}
4325:   DMPlexGetDepth(dm, &depth);
4326:   PetscSectionGetNumFields(section, &numFields);
4327:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4328:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4329:     return(0);
4330:   }
4331:   /* Get points */
4332:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4333:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4334:   /* Get array */
4335:   VecGetArray(v, &array);
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;

4343:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
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:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4391:     }
4392:   } else {
4393:     PetscInt dof, off;
4394:     const PetscInt    **perms = NULL;
4395:     const PetscScalar **flips = NULL;

4397:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
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:         PetscSectionGetDof(section, point, &dof);
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:         PetscSectionGetDof(section, point, &dof);
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:         PetscSectionGetDof(section, point, &dof);
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:         PetscSectionGetDof(section, point, &dof);
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:         PetscSectionGetDof(section, point, &dof);
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:         PetscSectionGetDof(section, point, &dof);
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:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4451:   }
4452:   /* Cleanup points */
4453:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4454:   /* Cleanup array */
4455:   VecRestoreArray(v, &array);
4456:   return(0);
4457: }

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;

4472:   if (!section) {DMGetDefaultSection(dm, &section);}
4475:   PetscSectionGetNumFields(section, &numFields);
4476:   /* Get points */
4477:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4478:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4479:   /* Get array */
4480:   VecGetArray(v, &array);
4481:   /* Get values */
4482:   for (f = 0; f < numFields; ++f) {
4483:     const PetscInt    **perms = NULL;
4484:     const PetscScalar **flips = NULL;

4486:     if (!fieldActive[f]) {
4487:       for (p = 0; p < numPoints*2; p += 2) {
4488:         PetscInt fdof;
4489:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4490:         offset += fdof;
4491:       }
4492:       continue;
4493:     }
4494:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
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:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4535:   }
4536:   /* Cleanup points */
4537:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4538:   /* Cleanup array */
4539:   VecRestoreArray(v, &array);
4540:   return(0);
4541: }

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;

4550:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4551:   PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);
4552:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4553:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4554:   numCIndices = numCIndices ? numCIndices : numRIndices;
4555:   for (i = 0; i < numRIndices; i++) {
4556:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4557:     for (j = 0; j < numCIndices; j++) {
4558: #if defined(PETSC_USE_COMPLEX)
4559:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4560: #else
4561:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4562: #endif
4563:     }
4564:     PetscViewerASCIIPrintf(viewer, "\n");
4565:   }
4566:   return(0);
4567: }

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;

4579:   PetscSectionGetDof(section, point, &dof);
4580:   PetscSectionGetConstraintDof(section, point, &cdof);
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:     PetscSectionGetConstraintIndices(section, point, &cdofs);
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:   return(0);
4613: }

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;

4622:   PetscSectionGetNumFields(section, &numFields);
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;

4629:     PetscSectionGetFieldDof(section, point, f, &fdof);
4630:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
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:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
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:   return(0);
4660: }

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;

4684:   PetscSectionGetNumFields(section, &numFields);

4686:   DMPlexGetAnchors(dm,&aSec,&aIS);
4687:   /* if there are point-to-point constraints */
4688:   if (aSec) {
4689:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4690:     ISGetIndices(aIS,&anchors);
4691:     PetscSectionGetChart(aSec,&aStart,&aEnd);
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;

4699:       PetscSectionGetDof(section,b,&bSecDof);
4700:       if (!bSecDof) {
4701:         continue;
4702:       }
4703:       if (b >= aStart && b < aEnd) {
4704:         PetscSectionGetDof(aSec,b,&bDof);
4705:       }
4706:       if (bDof) {
4707:         /* this point is constrained */
4708:         /* it is going to be replaced by its anchors */
4709:         PetscInt bOff, q;

4711:         anyConstrained = PETSC_TRUE;
4712:         newNumPoints  += bDof;
4713:         PetscSectionGetOffset(aSec,b,&bOff);
4714:         for (q = 0; q < bDof; q++) {
4715:           PetscInt a = anchors[bOff + q];
4716:           PetscInt aDof;

4718:           PetscSectionGetDof(section,a,&aDof);
4719:           newNumIndices += aDof;
4720:           for (f = 0; f < numFields; ++f) {
4721:             PetscInt fDof;

4723:             PetscSectionGetFieldDof(section, a, f, &fDof);
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;

4735:           PetscSectionGetFieldDof(section, b, f, &fDof);
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) {ISRestoreIndices(aIS,&anchors);}
4747:     return(0);
4748:   }

4750:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4751:   if (outNumIndices) *outNumIndices = newNumIndices;

4753:   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];

4755:   if (!outPoints && !outValues) {
4756:     if (offsets) {
4757:       for (f = 0; f <= numFields; f++) {
4758:         offsets[f] = newOffsets[f];
4759:       }
4760:     }
4761:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4762:     return(0);
4763:   }

4765:   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);

4767:   DMGetDefaultConstraints(dm, &cSec, &cMat);

4769:   /* workspaces */
4770:   if (numFields) {
4771:     for (f = 0; f < numFields; f++) {
4772:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
4773:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
4774:     }
4775:   }
4776:   else {
4777:     DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
4778:     DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);
4779:   }

4781:   /* get workspaces for the point-to-point matrices */
4782:   if (numFields) {
4783:     PetscInt totalOffset, totalMatOffset;

4785:     for (p = 0; p < numPoints; p++) {
4786:       PetscInt b    = points[2*p];
4787:       PetscInt bDof = 0, bSecDof;

4789:       PetscSectionGetDof(section,b,&bSecDof);
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:         PetscSectionGetDof(aSec, b, &bDof);
4799:       }
4800:       if (bDof) {
4801:         for (f = 0; f < numFields; f++) {
4802:           PetscInt fDof, q, bOff, allFDof = 0;

4804:           PetscSectionGetFieldDof(section, b, f, &fDof);
4805:           PetscSectionGetOffset(aSec, b, &bOff);
4806:           for (q = 0; q < bDof; q++) {
4807:             PetscInt a = anchors[bOff + q];
4808:             PetscInt aFDof;

4810:             PetscSectionGetFieldDof(section, a, f, &aFDof);
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;

4821:           PetscSectionGetFieldDof(section, b, f, &fDof);
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:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
4837:     }
4838:   }
4839:   else {
4840:     for (p = 0; p < numPoints; p++) {
4841:       PetscInt b    = points[2*p];
4842:       PetscInt bDof = 0, bSecDof;

4844:       PetscSectionGetDof(section,b,&bSecDof);
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:         PetscSectionGetDof(aSec, b, &bDof);
4852:       }
4853:       if (bDof) {
4854:         PetscInt bOff, q, allDof = 0;

4856:         PetscSectionGetOffset(aSec, b, &bOff);
4857:         for (q = 0; q < bDof; q++) {
4858:           PetscInt a = anchors[bOff + q], aDof;

4860:           PetscSectionGetDof(section, a, &aDof);
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:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
4878:   }

4880:   /* output arrays */
4881:   DMGetWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);

4883:   /* get the point-to-point matrices; construct newPoints */
4884:   PetscSectionGetMaxDof(aSec, &maxAnchor);
4885:   PetscSectionGetMaxDof(section, &maxDof);
4886:   DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);
4887:   DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
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;

4894:       PetscSectionGetDof(section, b, &bSecDof);
4895:       if (!bSecDof) {
4896:         continue;
4897:       }
4898:       if (b >= aStart && b < aEnd) {
4899:         PetscSectionGetDof(aSec, b, &bDof);
4900:       }
4901:       if (bDof) {
4902:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

4904:         fStart[0] = 0;
4905:         fEnd[0]   = 0;
4906:         for (f = 0; f < numFields; f++) {
4907:           PetscInt fDof;

4909:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
4910:           fStart[f+1] = fStart[f] + fDof;
4911:           fEnd[f+1]   = fStart[f+1];
4912:         }
4913:         PetscSectionGetOffset(cSec, b, &bOff);
4914:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

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];

4921:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4922:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4923:         }
4924:         PetscSectionGetOffset(aSec, b, &bOff);
4925:         for (q = 0; q < bDof; q++) {
4926:           PetscInt a = anchors[bOff + q], aOff;

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:           PetscSectionGetOffset(section, a, &aOff);
4932:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
4933:         }
4934:         newP += bDof;

4936:         if (outValues) {
4937:           /* get the point-to-point submatrix */
4938:           for (f = 0; f < numFields; f++) {
4939:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
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;

4955:       PetscSectionGetDof(section, b, &bSecDof);
4956:       if (!bSecDof) {
4957:         continue;
4958:       }
4959:       if (b >= aStart && b < aEnd) {
4960:         PetscSectionGetDof(aSec, b, &bDof);
4961:       }
4962:       if (bDof) {
4963:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

4965:         PetscSectionGetOffset(cSec, b, &bOff);
4966:         DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, indices);

4968:         PetscSectionGetOffset (aSec, b, &bOff);
4969:         for (q = 0; q < bDof; q++) {
4970:           PetscInt a = anchors[bOff + q], aOff;

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 */

4974:           newPoints[2*(newP + q)]     = a;
4975:           newPoints[2*(newP + q) + 1] = 0;
4976:           PetscSectionGetOffset(section, a, &aOff);
4977:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
4978:         }
4979:         newP += bDof;

4981:         /* get the point-to-point submatrix */
4982:         if (outValues) {
4983:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
4984:         }
4985:       }
4986:       else {
4987:         newPoints[2 * newP]     = b;
4988:         newPoints[2 * newP + 1] = o;
4989:         newP++;
4990:       }
4991:     }
4992:   }

4994:   if (outValues) {
4995:     DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
4996:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
4997:     /* multiply constraints on the right */
4998:     if (numFields) {
4999:       for (f = 0; f < numFields; f++) {
5000:         PetscInt oldOff = offsets[f];

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;

5008:           PetscSectionGetFieldDof(section,b,f,&dof);
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];

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;

5044:         PetscSectionGetDof(section,b,&dof);
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];

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:     }

5072:     if (multiplyLeft) {
5073:       DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5074:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5075:       /* multiply constraints transpose on the left */
5076:       if (numFields) {
5077:         for (f = 0; f < numFields; f++) {
5078:           PetscInt oldOff = offsets[f];

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;

5086:             PetscSectionGetFieldDof(section,b,f,&dof);
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];

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;

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;

5120:           PetscSectionGetDof(section,b,&dof);
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];

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:       }

5145:       DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5146:     }
5147:     else {
5148:       newValues = tmpValues;
5149:     }
5150:   }

5152:   /* clean up */
5153:   DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);
5154:   DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);

5156:   if (numFields) {
5157:     for (f = 0; f < numFields; f++) {
5158:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
5159:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
5160:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
5161:     }
5162:   }
5163:   else {
5164:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
5165:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
5166:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);
5167:   }
5168:   ISRestoreIndices(aIS,&anchors);

5170:   /* output */
5171:   if (outPoints) {
5172:     *outPoints = newPoints;
5173:   }
5174:   else {
5175:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5176:   }
5177:   if (outValues) {
5178:     *outValues = newValues;
5179:   }
5180:   for (f = 0; f <= numFields; f++) {
5181:     offsets[f] = newOffsets[f];
5182:   }
5183:   return(0);
5184: }

5186: /*@C
5187:   DMPlexGetClosureIndices - Get the indices in a vector v for all points in the closure of the given point

5189:   Not collective

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

5197:   Output parameters:
5198: + numIndices - The number of indices
5199: . indices - The indices
5200: - outOffsets - Field offset if not NULL

5202:   Note: Must call DMPlexRestoreClosureIndices() to free allocated memory

5204:   Level: advanced

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;

5226:   PetscSectionGetNumFields(section, &Nf);
5227:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5228:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5229:   /* Get points in closure */
5230:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5231:   /* Get number of indices and indices per field */
5232:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5233:     PetscInt dof, fdof;

5235:     PetscSectionGetDof(section, points[p], &dof);
5236:     for (f = 0; f < Nf; ++f) {
5237:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
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) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5248:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5249:   }
5250:   /* Correct for hanging node constraints */
5251:   {
5252:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5253:     if (numPointsNew) {
5254:       for (f = 0; f < PetscMax(1,Nf); f++) {
5255:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5256:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5257:       }
5258:       for (f = 0; f < PetscMax(1,Nf); f++) {
5259:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5260:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5261:       }
5262:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5263:       numPoints = numPointsNew;
5264:       Nind      = NindNew;
5265:       points    = pointsNew;
5266:     }
5267:   }
5268:   /* Calculate indices */
5269:   DMGetWorkArray(dm, Nind, PETSC_INT, indices);
5270:   if (Nf) {
5271:     if (outOffsets) {
5272:       PetscInt f;

5274:       for (f = 0; f <= Nf; f++) {
5275:         outOffsets[f] = offsets[f];
5276:       }
5277:     }
5278:     for (p = 0; p < numPoints; p++) {
5279:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
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;

5286:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
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) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5293:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5294:   }
5295:   if (numPointsNew) {
5296:     DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);
5297:   } else {
5298:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5299:   }
5300:   if (numIndices) *numIndices = Nind;
5301:   return(0);
5302: }

5304: /*@C
5305:   DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point

5307:   Not collective

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

5318:   Level: advanced

5320: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5321: @*/
5322: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5323: {

5329:   DMRestoreWorkArray(dm, 0, PETSC_INT, indices);
5330:   return(0);
5331: }

5333: /*@C
5334:   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'

5336:   Not collective

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

5347:   Fortran Notes:
5348:   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.

5350:   Level: intermediate

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;

5372:   if (!section) {DMGetDefaultSection(dm, &section);}
5374:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5377:   PetscSectionGetNumFields(section, &numFields);
5378:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5379:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5380:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5381:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5382:     PetscInt fdof;

5384:     PetscSectionGetDof(section, points[p], &dof);
5385:     for (f = 0; f < numFields; ++f) {
5386:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5387:       offsets[f+1] += fdof;
5388:     }
5389:     numIndices += dof;
5390:   }
5391:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5397:     else           {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5398:     if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5399:       PetscInt foffset = offsets[f];

5401:       for (p = 0; p < numPoints; p++) {
5402:         PetscInt point          = points[2*p], fdof;
5403:         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;

5405:         if (!numFields) {
5406:           PetscSectionGetDof(section,point,&fdof);
5407:         } else {
5408:           PetscSectionGetFieldDof(section,point,f,&fdof);
5409:         }
5410:         if (flip) {
5411:           PetscInt i, j, k;

5413:           if (!valCopy) {
5414:             DMGetWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
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];

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:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5432:   if (newNumPoints) {
5433:     if (valCopy) {
5434:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5435:     }
5436:     for (f = 0; f < PetscMax(1,numFields); f++) {
5437:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5438:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5439:     }
5440:     for (f = 0; f < PetscMax(1,numFields); f++) {
5441:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5442:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5443:     }
5444:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5445:     numPoints  = newNumPoints;
5446:     numIndices = newNumIndices;
5447:     points     = newPoints;
5448:     values     = newValues;
5449:   }
5450:   DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
5451:   if (numFields) {
5452:     for (p = 0; p < numPoints; p++) {
5453:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
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:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5460:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5461:     }
5462:   }
5463:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5464:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5465:   if (mesh->printFEM > 1) {
5466:     PetscInt i;
5467:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5468:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5469:     PetscPrintf(PETSC_COMM_SELF, "\n");
5470:   }
5471:   if (ierr) {
5472:     PetscMPIInt    rank;
5473:     PetscErrorCode ierr2;

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: 
5480:   }
5481:   for (f = 0; f < PetscMax(1,numFields); f++) {
5482:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5483:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5484:   }
5485:   if (newNumPoints) {
5486:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5487:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5488:   }
5489:   else {
5490:     if (valCopy) {
5491:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5492:     }
5493:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5494:   }
5495:   DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
5496:   return(0);
5497: }

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;

5513:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5515:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5517:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5519:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5522:   PetscSectionGetNumFields(fsection, &numFields);
5523:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5524:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5525:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5526:   /* Column indices */
5527:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5528:   maxFPoints = numCPoints;
5529:   /* Compress out points not in the section */
5530:   /*   TODO: Squeeze out points with 0 dof as well */
5531:   PetscSectionGetChart(csection, &pStart, &pEnd);
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;

5543:     PetscSectionGetDof(csection, cpoints[p], &dof);
5544:     if (!dof) continue;
5545:     for (f = 0; f < numFields; ++f) {
5546:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
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:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5554:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5555:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5556:   for (r = 0, q = 0; r < numSubcells; ++r) {
5557:     /* TODO Map from coarse to fine cells */
5558:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5559:     /* Compress out points not in the section */
5560:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5561:     for (p = 0; p < numFPoints*2; p += 2) {
5562:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5563:         PetscSectionGetDof(fsection, fpoints[p], &dof);
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:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5573:   }
5574:   numFPoints = q;
5575:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5576:     PetscInt fdof;

5578:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5579:     if (!dof) continue;
5580:     for (f = 0; f < numFields; ++f) {
5581:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5582:       foffsets[f+1] += fdof;
5583:     }
5584:     numFIndices += dof;
5585:   }
5586:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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:   DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5591:   DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5592:   if (numFields) {
5593:     const PetscInt **permsF[32] = {NULL};
5594:     const PetscInt **permsC[32] = {NULL};

5596:     for (f = 0; f < numFields; f++) {
5597:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5598:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5599:     }
5600:     for (p = 0; p < numFPoints; p++) {
5601:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
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:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
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:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5610:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5611:     }
5612:   } else {
5613:     const PetscInt **permsF = NULL;
5614:     const PetscInt **permsC = NULL;

5616:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5617:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5618:     for (p = 0, off = 0; p < numFPoints; p++) {
5619:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5621:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5622:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5623:     }
5624:     for (p = 0, off = 0; p < numCPoints; p++) {
5625:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5627:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5628:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5629:     }
5630:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5631:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5632:   }
5633:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5634:   /* TODO: flips */
5635:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5636:   if (ierr) {
5637:     PetscMPIInt    rank;
5638:     PetscErrorCode ierr2;

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: 
5646:   }
5647:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5648:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5649:   DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5650:   DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5651:   return(0);
5652: }

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;

5666:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5668:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5670:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5672:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5674:   PetscSectionGetNumFields(fsection, &numFields);
5675:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5676:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5677:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5678:   /* Column indices */
5679:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5680:   maxFPoints = numCPoints;
5681:   /* Compress out points not in the section */
5682:   /*   TODO: Squeeze out points with 0 dof as well */
5683:   PetscSectionGetChart(csection, &pStart, &pEnd);
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;

5695:     PetscSectionGetDof(csection, cpoints[p], &dof);
5696:     if (!dof) continue;
5697:     for (f = 0; f < numFields; ++f) {
5698:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
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:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5706:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5707:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5708:   for (r = 0, q = 0; r < numSubcells; ++r) {
5709:     /* TODO Map from coarse to fine cells */
5710:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5711:     /* Compress out points not in the section */
5712:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5713:     for (p = 0; p < numFPoints*2; p += 2) {
5714:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5715:         PetscSectionGetDof(fsection, fpoints[p], &dof);
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:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5725:   }
5726:   numFPoints = q;
5727:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5728:     PetscInt fdof;

5730:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5731:     if (!dof) continue;
5732:     for (f = 0; f < numFields; ++f) {
5733:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5734:       foffsets[f+1] += fdof;
5735:     }
5736:     numFIndices += dof;
5737:   }
5738:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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};

5746:     for (f = 0; f < numFields; f++) {
5747:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5748:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5749:     }
5750:     for (p = 0; p < numFPoints; p++) {
5751:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
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:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
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:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5760:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5761:     }
5762:   } else {
5763:     const PetscInt **permsF = NULL;
5764:     const PetscInt **permsC = NULL;

5766:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5767:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5768:     for (p = 0, off = 0; p < numFPoints; p++) {
5769:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5771:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
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;

5777:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5778:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5779:     }
5780:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5781:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5782:   }
5783:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5784:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5785:   return(0);
5786: }

5788: /*@
5789:   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid

5791:   Input Parameter:
5792: . dm - The DMPlex object

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

5800:   Level: developer

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;

5812:   DMGetDimension(dm, &dim);
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:   return(0);
5818: }

5820: /*@
5821:   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid

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

5830:   Level: developer

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;

5842:   DMGetDimension(dm, &dim);
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:   return(0);
5848: }

5850: /*@C
5851:   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)

5853:   Input Parameter:
5854: . dm   - The DMPlex object

5856:   Output Parameter:
5857: . cellHeight - The height of a cell

5859:   Level: developer

5861: .seealso DMPlexSetVTKCellHeight()
5862: @*/
5863: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5864: {
5865:   DM_Plex *mesh = (DM_Plex*) dm->data;

5870:   *cellHeight = mesh->vtkCellHeight;
5871:   return(0);
5872: }

5874: /*@C
5875:   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)

5877:   Input Parameters:
5878: + dm   - The DMPlex object
5879: - cellHeight - The height of a cell

5881:   Level: developer

5883: .seealso DMPlexGetVTKCellHeight()
5884: @*/
5885: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5886: {
5887:   DM_Plex *mesh = (DM_Plex*) dm->data;

5891:   mesh->vtkCellHeight = cellHeight;
5892:   return(0);
5893: }

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;

5903:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
5904:   PetscSectionSetChart(section, pStart, pEnd);
5905:   for (p = pStart; p < pEnd; ++p) {
5906:     PetscSectionSetDof(section, p, 1);
5907:   }
5908:   PetscSectionSetUp(section);
5909:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
5910:   PetscMalloc1(pEnd - pStart, &numbers);
5911:   for (p = pStart; p < pEnd; ++p) {
5912:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
5913:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5914:     else                       numbers[p-pStart] += shift;
5915:   }
5916:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
5917:   if (globalSize) {
5918:     PetscLayout layout;
5919:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
5920:     PetscLayoutGetSize(layout, globalSize);
5921:     PetscLayoutDestroy(&layout);
5922:   }
5923:   PetscSectionDestroy(&section);
5924:   PetscSectionDestroy(&globalSection);
5925:   return(0);
5926: }

5928: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5929: {
5930:   PetscInt       cellHeight, cStart, cEnd, cMax;

5934:   DMPlexGetVTKCellHeight(dm, &cellHeight);
5935:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5936:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5937:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5938:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
5939:   return(0);
5940: }

5942: /*@C
5943:   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process

5945:   Input Parameter:
5946: . dm   - The DMPlex object

5948:   Output Parameter:
5949: . globalCellNumbers - Global cell numbers for all cells on this process

5951:   Level: developer

5953: .seealso DMPlexGetVertexNumbering()
5954: @*/
5955: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5956: {
5957:   DM_Plex       *mesh = (DM_Plex*) dm->data;

5962:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
5963:   *globalCellNumbers = mesh->globalCellNumbers;
5964:   return(0);
5965: }

5967: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
5968: {
5969:   PetscInt       vStart, vEnd, vMax;

5974:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5975:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
5976:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
5977:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
5978:   return(0);
5979: }

5981: /*@C
5982:   DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process

5984:   Input Parameter:
5985: . dm   - The DMPlex object

5987:   Output Parameter:
5988: . globalVertexNumbers - Global vertex numbers for all vertices on this process

5990:   Level: developer

5992: .seealso DMPlexGetCellNumbering()
5993: @*/
5994: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5995: {
5996:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6001:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6002:   *globalVertexNumbers = mesh->globalVertexNumbers;
6003:   return(0);
6004: }

6006: /*@C
6007:   DMPlexCreatePointNumbering - Create a global numbering for all points on this process

6009:   Input Parameter:
6010: . dm   - The DMPlex object

6012:   Output Parameter:
6013: . globalPointNumbers - Global numbers for all points on this process

6015:   Level: developer

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;

6028:   DMPlexGetDepth(dm, &depth);
6029:   /* For unstratified meshes use dim instead of depth */
6030:   if (depth < 0) {DMGetDimension(dm, &depth);}
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;

6036:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6037:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6038:     shift += gsize;
6039:   }
6040:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6041:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6042:   return(0);
6043: }

6045: /*@
6046:   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.

6048:   Input Parameters:
6049:   + dm - The DMPlex object

6051:   Note: This is a useful diagnostic when creating meshes programmatically.

6053:   Level: developer

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;

6067:   DMPlexGetConeSection(dm, &coneSection);
6068:   DMPlexGetSupportSection(dm, &supportSection);
6069:   /* Check that point p is found in the support of its cone points, and vice versa */
6070:   DMPlexGetChart(dm, &pStart, &pEnd);
6071:   for (p = pStart; p < pEnd; ++p) {
6072:     DMPlexGetConeSize(dm, p, &coneSize);
6073:     DMPlexGetCone(dm, p, &cone);
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:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6081:       DMPlexGetSupport(dm, cone[c], &support);
6082:       for (s = 0; s < supportSize; ++s) {
6083:         if (support[s] == p) break;
6084:       }
6085:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6086:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6087:         for (s = 0; s < coneSize; ++s) {
6088:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6089:         }
6090:         PetscPrintf(PETSC_COMM_SELF, "\n");
6091:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6092:         for (s = 0; s < supportSize; ++s) {
6093:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6094:         }
6095:         PetscPrintf(PETSC_COMM_SELF, "\n");
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:     DMPlexGetSupportSize(dm, p, &supportSize);
6101:     DMPlexGetSupport(dm, p, &support);
6102:     for (s = 0; s < supportSize; ++s) {
6103:       DMPlexGetConeSize(dm, support[s], &coneSize);
6104:       DMPlexGetCone(dm, support[s], &cone);
6105:       for (c = 0; c < coneSize; ++c) {
6106:         if (cone[c] == p) break;
6107:       }
6108:       if (c >= coneSize) {
6109:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6110:         for (c = 0; c < supportSize; ++c) {
6111:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6112:         }
6113:         PetscPrintf(PETSC_COMM_SELF, "\n");
6114:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6115:         for (c = 0; c < coneSize; ++c) {
6116:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6117:         }
6118:         PetscPrintf(PETSC_COMM_SELF, "\n");
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:   PetscSectionGetStorageSize(coneSection, &csize);
6124:   PetscSectionGetStorageSize(supportSection, &ssize);
6125:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6126:   return(0);
6127: }

6129: /*@
6130:   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices

6132:   Input Parameters:
6133: + dm - The DMPlex object
6134: . isSimplex - Are the cells simplices or tensor products
6135: - cellHeight - Normally 0

6137:   Note: This is a useful diagnostic when creating meshes programmatically.

6139:   Level: developer

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;

6150:   DMGetDimension(dm, &dim);
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:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6159:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6160:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6161:   cMax = cMax >= 0 ? cMax : cEnd;
6162:   for (c = cStart; c < cMax; ++c) {
6163:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6165:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6166:     for (cl = 0; cl < closureSize*2; cl += 2) {
6167:       const PetscInt p = closure[cl];
6168:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6169:     }
6170:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
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;

6176:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6177:     for (cl = 0; cl < closureSize*2; cl += 2) {
6178:       const PetscInt p = closure[cl];
6179:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6180:     }
6181:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6182:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6183:   }
6184:   return(0);
6185: }

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

6190:   Input Parameters:
6191: + dm - The DMPlex object
6192: . isSimplex - Are the cells simplices or tensor products
6193: - cellHeight - Normally 0

6195:   Note: This is a useful diagnostic when creating meshes programmatically.

6197:   Level: developer

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;

6209:   DMGetDimension(dm, &dim);
6210:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6211:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6212:   for (h = cellHeight; h < dim; ++h) {
6213:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
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;

6219:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6220:       DMPlexGetConeSize(dm, c, &coneSize);
6221:       DMPlexGetCone(dm, c, &cone);
6222:       DMPlexGetConeOrientation(dm, c, &ornt);
6223:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
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:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
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;

6233:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
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:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6243:       }
6244:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6245:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6246:     }
6247:   }
6248:   return(0);
6249: }

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;

6268:   DMGetDefaultGlobalSection(dmFine, &gsf);
6269:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6270:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6271:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6273:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6274:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6275:   MatSetType(*interpolation, dmCoarse->mattype);
6276:   DMGetApplicationContext(dmFine, &ctx);

6278:   DMGetCoarseDM(dmFine, &cdm);
6279:   DMPlexGetRegularRefinement(dmFine, &regular);
6280:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6281:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6282:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6283:   /* Use naive scaling */
6284:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6285:   return(0);
6286: }

6288: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6289: {
6291:   VecScatter     ctx;

6294:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6295:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6296:   VecScatterDestroy(&ctx);
6297:   return(0);
6298: }

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;

6311:   DMGetNumFields(dm, &numFields);
6312:   if (!numFields) return(0);
6313:   /* FE and FV boundary conditions are handled slightly differently */
6314:   PetscMalloc1(numFields, &isFE);
6315:   for (f = 0; f < numFields; ++f) {
6316:     PetscObject  obj;
6317:     PetscClassId id;

6319:     DMGetField(dm, f, &obj);
6320:     PetscObjectGetClassId(obj, &id);
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:   DMPlexGetDepth(dm, &depth);
6327:   DMGetDimension(dm, &dim);
6328:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6329:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6330:   PetscDSGetNumBoundary(dm->prob, &numBd);
6331:   for (bd = 0; bd < numBd; ++bd) {
6332:     PetscInt                field;
6333:     DMBoundaryConditionType type;
6334:     const char             *labelName;
6335:     DMLabel                 label;

6337:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6338:     DMGetLabel(dm,labelName,&label);
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:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6344:   /* Constrain ghost cells for FV */
6345:   for (f = 0; f < numFields; ++f) {
6346:     PetscInt *newidx, c;

6348:     if (isFE[f] || cEndInterior < 0) continue;
6349:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6350:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6351:     bcFields[bc] = f;
6352:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
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;

6364:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6365:     DMGetLabel(dm, bdLabel, &label);
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:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6371:       PetscStrcmp(bdname, bdLabel, &duplicate);
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:       DMPlexLabelComplete(dm, label);
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;

6383:       bcFields[bc] = field;
6384:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6385:       for (v = 0; v < numValues; ++v) {
6386:         IS              tmp;
6387:         const PetscInt *idx;

6389:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6390:         if (!tmp) continue;
6391:         ISGetLocalSize(tmp, &n);
6392:         ISGetIndices(tmp, &idx);
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:         ISRestoreIndices(tmp, &idx);
6399:         ISDestroy(&tmp);
6400:       }
6401:       PetscMalloc1(newn,&newidx);
6402:       newn = 0;
6403:       for (v = 0; v < numValues; ++v) {
6404:         IS              tmp;
6405:         const PetscInt *idx;

6407:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6408:         if (!tmp) continue;
6409:         ISGetLocalSize(tmp, &n);
6410:         ISGetIndices(tmp, &idx);
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:         ISRestoreIndices(tmp, &idx);
6417:         ISDestroy(&tmp);
6418:       }
6419:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6420:     }
6421:   }
6422:   /* Handle discretization */
6423:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6424:   for (f = 0; f < numFields; ++f) {
6425:     PetscObject obj;

6427:     DMGetField(dm, f, &obj);
6428:     if (isFE[f]) {
6429:       PetscFE         fe = (PetscFE) obj;
6430:       const PetscInt *numFieldDof;
6431:       PetscInt        d;

6433:       PetscFEGetNumComponents(fe, &numComp[f]);
6434:       PetscFEGetNumDof(fe, &numFieldDof);
6435:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6436:     } else {
6437:       PetscFV fv = (PetscFV) obj;

6439:       PetscFVGetNumComponents(fv, &numComp[f]);
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:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6450:   for (f = 0; f < numFields; ++f) {
6451:     PetscFE     fe;
6452:     const char *name;

6454:     DMGetField(dm, f, (PetscObject *) &fe);
6455:     PetscObjectGetName((PetscObject) fe, &name);
6456:     PetscSectionSetFieldName(section, f, name);
6457:   }
6458:   DMSetDefaultSection(dm, section);
6459:   PetscSectionDestroy(&section);
6460:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6461:   PetscFree3(bcFields,bcPoints,bcComps);
6462:   PetscFree2(numComp,numDof);
6463:   PetscFree(isFE);
6464:   return(0);
6465: }

6467: /*@
6468:   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh

6470:   Input Parameter:
6471: . dm - The DMPlex object

6473:   Output Parameter:
6474: . regular - The flag

6476:   Level: intermediate

6478: .seealso: DMPlexSetRegularRefinement()
6479: @*/
6480: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6481: {
6485:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6486:   return(0);
6487: }

6489: /*@
6490:   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh

6492:   Input Parameters:
6493: + dm - The DMPlex object
6494: - regular - The flag

6496:   Level: intermediate

6498: .seealso: DMPlexGetRegularRefinement()
6499: @*/
6500: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6501: {
6504:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6505:   return(0);
6506: }

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().

6513:   not collective

6515:   Input Parameters:
6516: . dm - The DMPlex object

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


6523:   Level: intermediate

6525: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6526: @*/
6527: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6528: {
6529:   DM_Plex *plex = (DM_Plex *)dm->data;

6534:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6535:   if (anchorSection) *anchorSection = plex->anchorSection;
6536:   if (anchorIS) *anchorIS = plex->anchorIS;
6537:   return(0);
6538: }

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.

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.

6548:   collective on dm

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).

6555:   The reference counts of anchorSection and anchorIS are incremented.

6557:   Level: intermediate

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;

6569:   if (anchorSection) {
6571:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6572:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6573:   }
6574:   if (anchorIS) {
6576:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6577:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6578:   }

6580:   PetscObjectReference((PetscObject)anchorSection);
6581:   PetscSectionDestroy(&plex->anchorSection);
6582:   plex->anchorSection = anchorSection;

6584:   PetscObjectReference((PetscObject)anchorIS);
6585:   ISDestroy(&plex->anchorIS);
6586:   plex->anchorIS = anchorIS;

6588: #if defined(PETSC_USE_DEBUG)
6589:   if (anchorIS && anchorSection) {
6590:     PetscInt size, a, pStart, pEnd;
6591:     const PetscInt *anchors;

6593:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6594:     ISGetLocalSize(anchorIS,&size);
6595:     ISGetIndices(anchorIS,&anchors);
6596:     for (a = 0; a < size; a++) {
6597:       PetscInt p;

6599:       p = anchors[a];
6600:       if (p >= pStart && p < pEnd) {
6601:         PetscInt dof;

6603:         PetscSectionGetDof(anchorSection,p,&dof);
6604:         if (dof) {
6605:           PetscErrorCode ierr2;

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:     ISRestoreIndices(anchorIS,&anchors);
6613:   }
6614: #endif
6615:   /* reset the generic constraints */
6616:   DMSetDefaultConstraints(dm,NULL,NULL);
6617:   return(0);
6618: }

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;

6628:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6629:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6630:   PetscSectionGetNumFields(section,&numFields);
6631:   if (numFields) {
6632:     PetscInt f;
6633:     PetscSectionSetNumFields(*cSec,numFields);

6635:     for (f = 0; f < numFields; f++) {
6636:       PetscInt numComp;

6638:       PetscSectionGetFieldComponents(section,f,&numComp);
6639:       PetscSectionSetFieldComponents(*cSec,f,numComp);
6640:     }
6641:   }
6642:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6643:   PetscSectionGetChart(section,&sStart,&sEnd);
6644:   pStart = PetscMax(pStart,sStart);
6645:   pEnd   = PetscMin(pEnd,sEnd);
6646:   pEnd   = PetscMax(pStart,pEnd);
6647:   PetscSectionSetChart(*cSec,pStart,pEnd);
6648:   for (p = pStart; p < pEnd; p++) {
6649:     PetscSectionGetDof(anchorSection,p,&dof);
6650:     if (dof) {
6651:       PetscSectionGetDof(section,p,&dof);
6652:       PetscSectionSetDof(*cSec,p,dof);
6653:       for (f = 0; f < numFields; f++) {
6654:         PetscSectionGetFieldDof(section,p,f,&dof);
6655:         PetscSectionSetFieldDof(*cSec,p,f,dof);
6656:       }
6657:     }
6658:   }
6659:   PetscSectionSetUp(*cSec);
6660:   return(0);
6661: }

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;

6674:   PetscSectionGetStorageSize(cSec, &m);
6675:   PetscSectionGetStorageSize(section, &n);
6676:   MatCreate(PETSC_COMM_SELF,cMat);
6677:   MatSetSizes(*cMat,m,n,m,n);
6678:   MatSetType(*cMat,MATSEQAIJ);
6679:   DMPlexGetAnchors(dm,&aSec,&aIS);
6680:   ISGetIndices(aIS,&anchors);
6681:   /* cSec will be a subset of aSec and section */
6682:   PetscSectionGetChart(cSec,&pStart,&pEnd);
6683:   PetscMalloc1(m+1,&i);
6684:   i[0] = 0;
6685:   PetscSectionGetNumFields(section,&numFields);
6686:   for (p = pStart; p < pEnd; p++) {
6687:     PetscInt rDof, rOff, r;

6689:     PetscSectionGetDof(aSec,p,&rDof);
6690:     if (!rDof) continue;
6691:     PetscSectionGetOffset(aSec,p,&rOff);
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:           PetscSectionGetFieldDof(section,a,f,&aDof);
6698:           annz += aDof;
6699:         }
6700:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6701:         PetscSectionGetFieldOffset(cSec,p,f,&off);
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:         PetscSectionGetDof(section,a,&aDof);
6712:         annz += aDof;
6713:       }
6714:       PetscSectionGetDof(cSec,p,&dof);
6715:       PetscSectionGetOffset(cSec,p,&off);
6716:       for (q = 0; q < dof; q++) {
6717:         i[off + q + 1] = i[off + q] + annz;
6718:       }
6719:     }
6720:   }
6721:   nnz = i[m];
6722:   PetscMalloc1(nnz,&j);
6723:   offset = 0;
6724:   for (p = pStart; p < pEnd; p++) {
6725:     if (numFields) {
6726:       for (f = 0; f < numFields; f++) {
6727:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6728:         for (q = 0; q < dof; q++) {
6729:           PetscInt rDof, rOff, r;
6730:           PetscSectionGetDof(aSec,p,&rDof);
6731:           PetscSectionGetOffset(aSec,p,&rOff);
6732:           for (r = 0; r < rDof; r++) {
6733:             PetscInt s;

6735:             a = anchors[rOff + r];
6736:             PetscSectionGetFieldDof(section,a,f,&aDof);
6737:             PetscSectionGetFieldOffset(section,a,f,&aOff);
6738:             for (s = 0; s < aDof; s++) {
6739:               j[offset++] = aOff + s;
6740:             }
6741:           }
6742:         }
6743:       }
6744:     }
6745:     else {
6746:       PetscSectionGetDof(cSec,p,&dof);
6747:       for (q = 0; q < dof; q++) {
6748:         PetscInt rDof, rOff, r;
6749:         PetscSectionGetDof(aSec,p,&rDof);
6750:         PetscSectionGetOffset(aSec,p,&rOff);
6751:         for (r = 0; r < rDof; r++) {
6752:           PetscInt s;

6754:           a = anchors[rOff + r];
6755:           PetscSectionGetDof(section,a,&aDof);
6756:           PetscSectionGetOffset(section,a,&aOff);
6757:           for (s = 0; s < aDof; s++) {
6758:             j[offset++] = aOff + s;
6759:           }
6760:         }
6761:       }
6762:     }
6763:   }
6764:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
6765:   PetscFree(i);
6766:   PetscFree(j);
6767:   ISRestoreIndices(aIS,&anchors);
6768:   return(0);
6769: }

6771: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6772: {
6773:   DM_Plex        *plex = (DM_Plex *)dm->data;
6774:   PetscSection   anchorSection, section, cSec;
6775:   Mat            cMat;

6780:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6781:   if (anchorSection) {
6782:     PetscDS  ds;
6783:     PetscInt nf;

6785:     DMGetDefaultSection(dm,&section);
6786:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
6787:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
6788:     DMGetDS(dm,&ds);
6789:     PetscDSGetNumFields(ds,&nf);
6790:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
6791:     DMSetDefaultConstraints(dm,cSec,cMat);
6792:     PetscSectionDestroy(&cSec);
6793:     MatDestroy(&cMat);
6794:   }
6795:   return(0);
6796: }