Actual source code: plex.c

petsc-master 2016-07-29
Report Typos and Errors
  1: #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
  2: #include <petsc/private/isimpl.h>
  3: #include <petsc/private/vecimpl.h>
  4: #include <petscsf.h>
  5: #include <petscds.h>
  6: #include <petscdraw.h>

  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_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);
 12: PETSC_EXTERN PetscErrorCode VecLoad_Default(Vec, PetscViewer);

 16: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
 17: {
 18:   PetscInt       dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior, vdof = 0, cdof = 0;

 22:   *ft  = PETSC_VTK_POINT_FIELD;
 23:   DMGetDimension(dm, &dim);
 24:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
 25:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
 26:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
 27:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
 28:   PetscSectionGetChart(section, &pStart, &pEnd);
 29:   if (field >= 0) {
 30:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vdof);}
 31:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &cdof);}
 32:   } else {
 33:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vdof);}
 34:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &cdof);}
 35:   }
 36:   if (vdof) {
 37:     *sStart = vStart;
 38:     *sEnd   = vEnd;
 39:     if (vdof == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
 40:     else             *ft = PETSC_VTK_POINT_FIELD;
 41:   } else if (cdof) {
 42:     *sStart = cStart;
 43:     *sEnd   = cEnd;
 44:     if (cdof == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
 45:     else             *ft = PETSC_VTK_CELL_FIELD;
 46:   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
 47:   return(0);
 48: }

 52: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
 53: {
 54:   DM             dm;
 55:   PetscBool      isvtk, ishdf5, isseq;

 59:   VecGetDM(v, &dm);
 60:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
 61:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
 62:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
 63:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
 64:   if (isvtk || ishdf5) {
 65:     PetscInt  numFields;
 66:     PetscBool fem = PETSC_FALSE;

 68:     DMGetNumFields(dm, &numFields);
 69:     if (numFields) {
 70:       PetscObject fe;

 72:       DMGetField(dm, 0, &fe);
 73:       if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE;
 74:     }
 75:     if (fem) {DMPlexInsertBoundaryValues(dm, PETSC_TRUE, v, 0.0, NULL, NULL, NULL);}
 76:   }
 77:   if (isvtk) {
 78:     PetscSection            section;
 79:     PetscViewerVTKFieldType ft;
 80:     PetscInt                pStart, pEnd;

 82:     DMGetDefaultSection(dm, &section);
 83:     DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
 84:     PetscObjectReference((PetscObject) dm); /* viewer drops reference */
 85:     PetscObjectReference((PetscObject) v);  /* viewer drops reference */
 86:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
 87:   } else if (ishdf5) {
 88: #if defined(PETSC_HAVE_HDF5)
 89:     VecView_Plex_Local_HDF5(v, viewer);
 90: #else
 91:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
 92: #endif
 93:   } else {
 94:     if (isseq) {VecView_Seq(v, viewer);}
 95:     else       {VecView_MPI(v, viewer);}
 96:   }
 97:   return(0);
 98: }

102: PetscErrorCode VecView_Plex_Draw(Vec v, PetscViewer viewer)
103: {
104:   DM                 dm;
105:   PetscDraw          draw, popup;
106:   DM                 cdm;
107:   PetscSection       coordSection;
108:   Vec                coordinates;
109:   const PetscScalar *coords, *array;
110:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
111:   PetscReal          min, max;
112:   PetscBool          isnull;
113:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N, level;
114:   const char        *name;
115:   PetscErrorCode     ierr;

118:   VecGetDM(v, &dm);
119:   DMGetCoordinateDim(dm, &dim);
120:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
121:   DMGetCoarsenLevel(dm, &level);
122:   DMGetCoordinateDM(dm, &cdm);
123:   DMGetDefaultSection(cdm, &coordSection);
124:   DMGetCoordinatesLocal(dm, &coordinates);
125:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
126:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

128:   PetscViewerDrawGetDraw(viewer, 0, &draw);
129:   PetscDrawIsNull(draw, &isnull);
130:   if (isnull) return(0);
131:   PetscObjectGetName((PetscObject) v, &name);
132:   PetscDrawSetTitle(draw, name);

134:   VecGetLocalSize(coordinates, &N);
135:   VecGetArrayRead(coordinates, &coords);
136:   for (c = 0; c < N; c += dim) {
137:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
138:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
139:   }
140:   VecRestoreArrayRead(coordinates, &coords);
141:   PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
142:   PetscDrawClear(draw);

144:   VecMin(v, NULL, &min);
145:   VecMax(v, NULL, &max);
146:   PetscDrawGetPopup(draw, &popup);
147:   PetscDrawScalePopup(popup, min, max);

149:   VecGetArrayRead(v, &array);
150:   for (c = cStart; c < cEnd; ++c) {
151:     PetscScalar *coords = NULL, *a = NULL;
152:     PetscInt     numCoords, color;

154:     DMPlexPointGlobalRead(dm, c, array, &a);
155:     color = PetscDrawRealToColor(PetscRealPart(a[0]), min, max);
156:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
157:     switch (numCoords) {
158:     case 6:
159:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color, color, color);
160:       break;
161:     case 8:
162:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color, color, color);
163:       PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color, color, color);
164:       break;
165:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
166:     }
167:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
168:   }
169:   VecRestoreArrayRead(v, &array);
170:   PetscDrawFlush(draw);
171:   PetscDrawPause(draw);
172:   PetscDrawSave(draw);
173:   return(0);
174: }

178: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
179: {
180:   DM             dm;
181:   PetscBool      isvtk, ishdf5, isdraw, isseq;

185:   VecGetDM(v, &dm);
186:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
187:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
188:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
189:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
190:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
191:   if (isvtk) {
192:     Vec         locv;
193:     const char *name;

195:     DMGetLocalVector(dm, &locv);
196:     PetscObjectGetName((PetscObject) v, &name);
197:     PetscObjectSetName((PetscObject) locv, name);
198:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
199:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
200:     VecView_Plex_Local(locv, viewer);
201:     DMRestoreLocalVector(dm, &locv);
202:   } else if (ishdf5) {
203: #if defined(PETSC_HAVE_HDF5)
204:     VecView_Plex_HDF5(v, viewer);
205: #else
206:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
207: #endif
208:   } else if (isdraw) {
209:     VecView_Plex_Draw(v, viewer);
210:   } else {
211:     if (isseq) {VecView_Seq(v, viewer);}
212:     else       {VecView_MPI(v, viewer);}
213:   }
214:   return(0);
215: }

219: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
220: {
221:   DM                dm;
222:   MPI_Comm          comm;
223:   PetscViewerFormat format;
224:   Vec               v;
225:   PetscBool         isvtk, ishdf5;
226:   PetscErrorCode    ierr;

229:   VecGetDM(originalv, &dm);
230:   PetscObjectGetComm((PetscObject) originalv, &comm);
231:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
232:   PetscViewerGetFormat(viewer, &format);
233:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
234:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
235:   if (format == PETSC_VIEWER_NATIVE) {
236:     const char *vecname;
237:     PetscInt    n, nroots;

239:     if (dm->sfNatural) {
240:       VecGetLocalSize(originalv, &n);
241:       PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
242:       if (n == nroots) {
243:         DMGetGlobalVector(dm, &v);
244:         DMPlexGlobalToNaturalBegin(dm, originalv, v);
245:         DMPlexGlobalToNaturalEnd(dm, originalv, v);
246:         PetscObjectGetName((PetscObject) originalv, &vecname);
247:         PetscObjectSetName((PetscObject) v, vecname);
248:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
249:     } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
250:   } else {
251:     /* we are viewing a natural DMPlex vec. */
252:     v = originalv;
253:   }
254:   if (ishdf5) {
255: #if defined(PETSC_HAVE_HDF5)
256:     VecView_Plex_HDF5_Native(v, viewer);
257: #else
258:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
259: #endif
260:   } else if (isvtk) {
261:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
262:   } else {
263:     PetscBool isseq;

265:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
266:     if (isseq) {VecView_Seq(v, viewer);}
267:     else       {VecView_MPI(v, viewer);}
268:   }
269:   if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
270:   return(0);
271: }

275: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
276: {
277:   DM             dm;
278:   PetscBool      ishdf5;

282:   VecGetDM(v, &dm);
283:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
284:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
285:   if (ishdf5) {
286:     DM          dmBC;
287:     Vec         gv;
288:     const char *name;

290:     DMGetOutputDM(dm, &dmBC);
291:     DMGetGlobalVector(dmBC, &gv);
292:     PetscObjectGetName((PetscObject) v, &name);
293:     PetscObjectSetName((PetscObject) gv, name);
294:     VecLoad_Default(gv, viewer);
295:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
296:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
297:     DMRestoreGlobalVector(dmBC, &gv);
298:   } else {
299:     VecLoad_Default(v, viewer);
300:   }
301:   return(0);
302: }

306: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
307: {
308:   DM             dm;
309:   PetscBool      ishdf5;

313:   VecGetDM(v, &dm);
314:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
315:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
316:   if (ishdf5) {
317: #if defined(PETSC_HAVE_HDF5)
318:     VecLoad_Plex_HDF5(v, viewer);
319: #else
320:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
321: #endif
322:   } else {
323:     VecLoad_Default(v, viewer);
324:   }
325:   return(0);
326: }

330: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
331: {
332:   DM                dm;
333:   PetscViewerFormat format;
334:   PetscBool         ishdf5;
335:   PetscErrorCode    ierr;

338:   VecGetDM(originalv, &dm);
339:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
340:   PetscViewerGetFormat(viewer, &format);
341:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
342:   if (format == PETSC_VIEWER_NATIVE) {
343:     if (dm->sfNatural) {
344:       if (ishdf5) {
345: #if defined(PETSC_HAVE_HDF5)
346:         Vec         v;
347:         const char *vecname;

349:         DMGetGlobalVector(dm, &v);
350:         PetscObjectGetName((PetscObject) originalv, &vecname);
351:         PetscObjectSetName((PetscObject) v, vecname);
352:         VecLoad_Plex_HDF5_Native(v, viewer);
353:         DMPlexNaturalToGlobalBegin(dm, v, originalv);
354:         DMPlexNaturalToGlobalEnd(dm, v, originalv);
355:         DMRestoreGlobalVector(dm, &v);
356: #else
357:         SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
358: #endif
359:       } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
360:     }
361:   }
362:   return(0);
363: }

367: PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
368: {
369:   PetscSection       coordSection;
370:   Vec                coordinates;
371:   DMLabel            depthLabel;
372:   const char        *name[4];
373:   const PetscScalar *a;
374:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
375:   PetscErrorCode     ierr;

378:   DMGetDimension(dm, &dim);
379:   DMGetCoordinatesLocal(dm, &coordinates);
380:   DMGetCoordinateSection(dm, &coordSection);
381:   DMPlexGetDepthLabel(dm, &depthLabel);
382:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
383:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
384:   VecGetArrayRead(coordinates, &a);
385:   name[0]     = "vertex";
386:   name[1]     = "edge";
387:   name[dim-1] = "face";
388:   name[dim]   = "cell";
389:   for (c = cStart; c < cEnd; ++c) {
390:     PetscInt *closure = NULL;
391:     PetscInt  closureSize, cl;

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

399:       if ((point < pStart) || (point >= pEnd)) continue;
400:       PetscSectionGetDof(coordSection, point, &dof);
401:       if (!dof) continue;
402:       DMLabelGetValue(depthLabel, point, &depth);
403:       PetscSectionGetOffset(coordSection, point, &off);
404:       PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
405:       for (p = 0; p < dof/dim; ++p) {
406:         PetscViewerASCIIPrintf(viewer, " (");
407:         for (d = 0; d < dim; ++d) {
408:           if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
409:           PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
410:         }
411:         PetscViewerASCIIPrintf(viewer, ")");
412:       }
413:       PetscViewerASCIIPrintf(viewer, "\n");
414:     }
415:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
416:     PetscViewerASCIIPopTab(viewer);
417:   }
418:   VecRestoreArrayRead(coordinates, &a);
419:   return(0);
420: }

424: PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
425: {
426:   DM_Plex          *mesh = (DM_Plex*) dm->data;
427:   DM                cdm;
428:   DMLabel           markers;
429:   PetscSection      coordSection;
430:   Vec               coordinates;
431:   PetscViewerFormat format;
432:   PetscErrorCode    ierr;

435:   DMGetCoordinateDM(dm, &cdm);
436:   DMGetDefaultSection(cdm, &coordSection);
437:   DMGetCoordinatesLocal(dm, &coordinates);
438:   PetscViewerGetFormat(viewer, &format);
439:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
440:     const char *name;
441:     PetscInt    maxConeSize, maxSupportSize;
442:     PetscInt    pStart, pEnd, p;
443:     PetscMPIInt rank, size;

445:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
446:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
447:     PetscObjectGetName((PetscObject) dm, &name);
448:     DMPlexGetChart(dm, &pStart, &pEnd);
449:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
450:     PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);
451:     PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
452:     PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
453:     PetscViewerASCIIPushSynchronized(viewer);
454:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);
455:     for (p = pStart; p < pEnd; ++p) {
456:       PetscInt dof, off, s;

458:       PetscSectionGetDof(mesh->supportSection, p, &dof);
459:       PetscSectionGetOffset(mesh->supportSection, p, &off);
460:       for (s = off; s < off+dof; ++s) {
461:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
462:       }
463:     }
464:     PetscViewerFlush(viewer);
465:     PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
466:     for (p = pStart; p < pEnd; ++p) {
467:       PetscInt dof, off, c;

469:       PetscSectionGetDof(mesh->coneSection, p, &dof);
470:       PetscSectionGetOffset(mesh->coneSection, p, &off);
471:       for (c = off; c < off+dof; ++c) {
472:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
473:       }
474:     }
475:     PetscViewerFlush(viewer);
476:     PetscViewerASCIIPopSynchronized(viewer);
477:     PetscSectionGetChart(coordSection, &pStart, NULL);
478:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
479:     DMGetLabel(dm, "marker", &markers);
480:     DMLabelView(markers,viewer);
481:     if (size > 1) {
482:       PetscSF sf;

484:       DMGetPointSF(dm, &sf);
485:       PetscSFView(sf, viewer);
486:     }
487:     PetscViewerFlush(viewer);
488:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
489:     const char  *name, *color;
490:     const char  *defcolors[3]  = {"gray", "orange", "green"};
491:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
492:     PetscReal    scale         = 2.0;
493:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
494:     double       tcoords[3];
495:     PetscScalar *coords;
496:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
497:     PetscMPIInt  rank, size;
498:     char         **names, **colors, **lcolors;

500:     DMGetDimension(dm, &dim);
501:     DMPlexGetDepth(dm, &depth);
502:     DMGetNumLabels(dm, &numLabels);
503:     numLabels  = PetscMax(numLabels, 10);
504:     numColors  = 10;
505:     numLColors = 10;
506:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
507:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
508:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
509:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
510:     if (!useLabels) numLabels = 0;
511:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
512:     if (!useColors) {
513:       numColors = 3;
514:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
515:     }
516:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
517:     if (!useColors) {
518:       numLColors = 4;
519:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
520:     }
521:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
522:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
523:     PetscObjectGetName((PetscObject) dm, &name);
524:     PetscViewerASCIIPrintf(viewer, "\
525: \\documentclass[tikz]{standalone}\n\n\
526: \\usepackage{pgflibraryshapes}\n\
527: \\usetikzlibrary{backgrounds}\n\
528: \\usetikzlibrary{arrows}\n\
529: \\begin{document}\n");
530:     if (size > 1) {
531:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
532:       for (p = 0; p < size; ++p) {
533:         if (p > 0 && p == size-1) {
534:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
535:         } else if (p > 0) {
536:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
537:         }
538:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
539:       }
540:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
541:     }
542:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);
543:     /* Plot vertices */
544:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
545:     VecGetArray(coordinates, &coords);
546:     PetscViewerASCIIPushSynchronized(viewer);
547:     for (v = vStart; v < vEnd; ++v) {
548:       PetscInt  off, dof, d;
549:       PetscBool isLabeled = PETSC_FALSE;

551:       PetscSectionGetDof(coordSection, v, &dof);
552:       PetscSectionGetOffset(coordSection, v, &off);
553:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
554:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
555:       for (d = 0; d < dof; ++d) {
556:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
557:         tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
558:       }
559:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
560:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
561:       for (d = 0; d < dof; ++d) {
562:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
563:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
564:       }
565:       color = colors[rank%numColors];
566:       for (l = 0; l < numLabels; ++l) {
567:         PetscInt val;
568:         DMGetLabelValue(dm, names[l], v, &val);
569:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
570:       }
571:       if (useNumbers) {
572:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
573:       } else {
574:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
575:       }
576:     }
577:     VecRestoreArray(coordinates, &coords);
578:     PetscViewerFlush(viewer);
579:     /* Plot edges */
580:     if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
581:     if (dim < 3 && useNumbers) {
582:       VecGetArray(coordinates, &coords);
583:       PetscViewerASCIIPrintf(viewer, "\\path\n");
584:       for (e = eStart; e < eEnd; ++e) {
585:         const PetscInt *cone;
586:         PetscInt        coneSize, offA, offB, dof, d;

588:         DMPlexGetConeSize(dm, e, &coneSize);
589:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
590:         DMPlexGetCone(dm, e, &cone);
591:         PetscSectionGetDof(coordSection, cone[0], &dof);
592:         PetscSectionGetOffset(coordSection, cone[0], &offA);
593:         PetscSectionGetOffset(coordSection, cone[1], &offB);
594:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
595:         for (d = 0; d < dof; ++d) {
596:           tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
597:           tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
598:         }
599:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
600:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
601:         for (d = 0; d < dof; ++d) {
602:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
603:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
604:         }
605:         color = colors[rank%numColors];
606:         for (l = 0; l < numLabels; ++l) {
607:           PetscInt val;
608:           DMGetLabelValue(dm, names[l], v, &val);
609:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
610:         }
611:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
612:       }
613:       VecRestoreArray(coordinates, &coords);
614:       PetscViewerFlush(viewer);
615:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
616:     }
617:     /* Plot cells */
618:     if (dim == 3 || !useNumbers) {
619:       for (e = eStart; e < eEnd; ++e) {
620:         const PetscInt *cone;

622:         color = colors[rank%numColors];
623:         for (l = 0; l < numLabels; ++l) {
624:           PetscInt val;
625:           DMGetLabelValue(dm, names[l], e, &val);
626:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
627:         }
628:         DMPlexGetCone(dm, e, &cone);
629:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
630:       }
631:     } else {
632:       DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
633:       for (c = cStart; c < cEnd; ++c) {
634:         PetscInt *closure = NULL;
635:         PetscInt  closureSize, firstPoint = -1;

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

642:           if ((point < vStart) || (point >= vEnd)) continue;
643:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
644:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
645:           if (firstPoint < 0) firstPoint = point;
646:         }
647:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
648:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
649:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
650:       }
651:     }
652:     PetscViewerFlush(viewer);
653:     PetscViewerASCIIPopSynchronized(viewer);
654:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
655:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
656:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
657:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
658:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
659:     PetscFree3(names, colors, lcolors);
660:   } else {
661:     MPI_Comm    comm;
662:     PetscInt   *sizes, *hybsizes;
663:     PetscInt    locDepth, depth, dim, d, pMax[4];
664:     PetscInt    pStart, pEnd, p;
665:     PetscInt    numLabels, l;
666:     const char *name;
667:     PetscMPIInt size;

669:     PetscObjectGetComm((PetscObject)dm,&comm);
670:     MPI_Comm_size(comm, &size);
671:     DMGetDimension(dm, &dim);
672:     PetscObjectGetName((PetscObject) dm, &name);
673:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);}
674:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);}
675:     DMPlexGetDepth(dm, &locDepth);
676:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
677:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);
678:     PetscMalloc2(size,&sizes,size,&hybsizes);
679:     if (depth == 1) {
680:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
681:       pEnd = pEnd - pStart;
682:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
683:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
684:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
685:       PetscViewerASCIIPrintf(viewer, "\n");
686:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
687:       pEnd = pEnd - pStart;
688:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
689:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
690:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
691:       PetscViewerASCIIPrintf(viewer, "\n");
692:     } else {
693:       for (d = 0; d <= dim; d++) {
694:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
695:         pEnd    -= pStart;
696:         pMax[d] -= pStart;
697:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
698:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
699:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
700:         for (p = 0; p < size; ++p) {
701:           if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
702:           else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
703:         }
704:         PetscViewerASCIIPrintf(viewer, "\n");
705:       }
706:     }
707:     PetscFree2(sizes,hybsizes);
708:     DMGetNumLabels(dm, &numLabels);
709:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
710:     for (l = 0; l < numLabels; ++l) {
711:       DMLabel         label;
712:       const char     *name;
713:       IS              valueIS;
714:       const PetscInt *values;
715:       PetscInt        numValues, v;

717:       DMGetLabelName(dm, l, &name);
718:       DMGetLabel(dm, name, &label);
719:       DMLabelGetNumValues(label, &numValues);
720:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata of sizes (", name, numValues);
721:       DMLabelGetValueIS(label, &valueIS);
722:       ISGetIndices(valueIS, &values);
723:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
724:       for (v = 0; v < numValues; ++v) {
725:         PetscInt size;

727:         DMLabelGetStratumSize(label, values[v], &size);
728:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
729:         PetscViewerASCIIPrintf(viewer, "%D", size);
730:       }
731:       PetscViewerASCIIPrintf(viewer, ")\n");
732:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
733:       ISRestoreIndices(valueIS, &values);
734:       ISDestroy(&valueIS);
735:     }
736:     DMGetCoarseDM(dm, &cdm);
737:     if (cdm) {
738:       PetscViewerASCIIPushTab(viewer);
739:       DMPlexView_Ascii(cdm, viewer);
740:       PetscViewerASCIIPopTab(viewer);
741:     }
742:   }
743:   return(0);
744: }

748: PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
749: {
750:   PetscDraw          draw;
751:   DM                 cdm;
752:   PetscSection       coordSection;
753:   Vec                coordinates;
754:   const PetscScalar *coords;
755:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
756:   PetscBool          isnull;
757:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
758:   PetscErrorCode     ierr;

761:   DMGetCoordinateDim(dm, &dim);
762:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
763:   DMGetCoordinateDM(dm, &cdm);
764:   DMGetDefaultSection(cdm, &coordSection);
765:   DMGetCoordinatesLocal(dm, &coordinates);
766:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
767:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

769:   PetscViewerDrawGetDraw(viewer, 0, &draw);
770:   PetscDrawIsNull(draw, &isnull);
771:   if (isnull) return(0);
772:   PetscDrawSetTitle(draw, "Mesh");

774:   VecGetLocalSize(coordinates, &N);
775:   VecGetArrayRead(coordinates, &coords);
776:   for (c = 0; c < N; c += dim) {
777:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
778:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
779:   }
780:   VecRestoreArrayRead(coordinates, &coords);
781:   PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
782:   PetscDrawClear(draw);

784:   for (c = cStart; c < cEnd; ++c) {
785:     PetscScalar *coords = NULL;
786:     PetscInt     numCoords;

788:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
789:     switch (numCoords) {
790:     case 6:
791:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
792:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
793:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
794:       break;
795:     case 8:
796:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
797:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
798:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
799:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
800:       break;
801:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
802:     }
803:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
804:   }
805:   PetscDrawFlush(draw);
806:   PetscDrawPause(draw);
807:   PetscDrawSave(draw);
808:   return(0);
809: }

813: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
814: {
815:   PetscBool      iascii, ishdf5, isvtk, isdraw;

821:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
822:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
823:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
824:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
825:   if (iascii) {
826:     DMPlexView_Ascii(dm, viewer);
827:   } else if (ishdf5) {
828: #if defined(PETSC_HAVE_HDF5)
829:     PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
830:     DMPlexView_HDF5(dm, viewer);
831:     PetscViewerPopFormat(viewer);
832: #else
833:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
834: #endif
835:   } else if (isvtk) {
836:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
837:   } else if (isdraw) {
838:     DMPlexView_Draw(dm, viewer);
839:   }
840:   return(0);
841: }

845: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
846: {
847:   PetscBool      isbinary, ishdf5;

853:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
854:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
855:   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
856:   else if (ishdf5) {
857: #if defined(PETSC_HAVE_HDF5)
858:     DMPlexLoad_HDF5(dm, viewer);
859: #else
860:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
861: #endif
862:   }
863:   return(0);
864: }


869: PetscErrorCode DMDestroy_Plex(DM dm)
870: {
871:   DM_Plex       *mesh = (DM_Plex*) dm->data;

875:   if (--mesh->refct > 0) return(0);
876:   PetscSectionDestroy(&mesh->coneSection);
877:   PetscFree(mesh->cones);
878:   PetscFree(mesh->coneOrientations);
879:   PetscSectionDestroy(&mesh->supportSection);
880:   PetscSectionDestroy(&mesh->subdomainSection);
881:   PetscFree(mesh->supports);
882:   PetscFree(mesh->facesTmp);
883:   PetscFree(mesh->tetgenOpts);
884:   PetscFree(mesh->triangleOpts);
885:   PetscPartitionerDestroy(&mesh->partitioner);
886:   DMLabelDestroy(&mesh->subpointMap);
887:   ISDestroy(&mesh->globalVertexNumbers);
888:   ISDestroy(&mesh->globalCellNumbers);
889:   PetscSectionDestroy(&mesh->anchorSection);
890:   ISDestroy(&mesh->anchorIS);
891:   PetscSectionDestroy(&mesh->parentSection);
892:   PetscFree(mesh->parents);
893:   PetscFree(mesh->childIDs);
894:   PetscSectionDestroy(&mesh->childSection);
895:   PetscFree(mesh->children);
896:   DMDestroy(&mesh->referenceTree);
897:   PetscGridHashDestroy(&mesh->lbox);
898:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
899:   PetscFree(mesh);
900:   PetscObjectComposeFunction((PetscObject)dm,"DMAdaptLabel_C",NULL);
901:   return(0);
902: }

906: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
907: {
908:   PetscSection           sectionGlobal;
909:   PetscInt               bs = -1, mbs;
910:   PetscInt               localSize;
911:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
912:   PetscErrorCode         ierr;
913:   MatType                mtype;
914:   ISLocalToGlobalMapping ltog;

917:   MatInitializePackage();
918:   mtype = dm->mattype;
919:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
920:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
921:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
922:   MatCreate(PetscObjectComm((PetscObject)dm), J);
923:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
924:   MatSetType(*J, mtype);
925:   MatSetFromOptions(*J);
926:   MatGetBlockSize(*J, &mbs);
927:   if (mbs > 1) bs = mbs;
928:   PetscStrcmp(mtype, MATSHELL, &isShell);
929:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
930:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
931:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
932:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
933:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
934:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
935:   PetscStrcmp(mtype, MATIS, &isMatIS);
936:   if (!isShell) {
937:     PetscSection subSection;
938:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
939:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin, *ltogidx, lsize;
940:     PetscInt     pStart, pEnd, p, dof, cdof;

942:     /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
943:     if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
944:       PetscSection section;
945:       PetscInt     size;

947:       DMGetDefaultSection(dm, &section);
948:       PetscSectionGetStorageSize(section, &size);
949:       PetscMalloc1(size,&ltogidx);
950:       DMPlexGetSubdomainSection(dm, &subSection);
951:     } else {
952:       DMGetLocalToGlobalMapping(dm,&ltog);
953:     }
954:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
955:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
956:       PetscInt bdof;

958:       PetscSectionGetDof(sectionGlobal, p, &dof);
959:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
960:       dof  = dof < 0 ? -(dof+1) : dof;
961:       bdof = cdof && (dof-cdof) ? 1 : dof;
962:       if (dof) {
963:         if (bs < 0)          {bs = bdof;}
964:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
965:       }
966:       if (isMatIS) {
967:         PetscInt loff,c,off;
968:         PetscSectionGetOffset(subSection, p, &loff);
969:         PetscSectionGetOffset(sectionGlobal, p, &off);
970:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
971:       }
972:     }
973:     /* Must have same blocksize on all procs (some might have no points) */
974:     bsLocal = bs;
975:     MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
976:     bsLocal = bs < 0 ? bsMax : bs;
977:     MPIU_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
978:     if (bsMin != bsMax) {bs = 1;}
979:     else                {bs = bsMax;}
980:     if (isMatIS) {
981:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs < 0 ? 1 : bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
982:     }
983:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
984:     if (isMatIS) {
985:       ISLocalToGlobalMappingDestroy(&ltog);
986:     }
987:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
988:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
989:     PetscFree4(dnz, onz, dnzu, onzu);
990:   }
991:   return(0);
992: }

996: /*
997:   DMPlexGetSubdomainGlobalSection - Returns the section associated with the subdomain

999:   Not collective

1001:   Input Parameter:
1002: . mesh - The DMPlex

1004:   Output Parameters:
1005: . subsection - The subdomain section

1007:   Level: developer

1009: .seealso:
1010: */
1011: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1012: {
1013:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1018:   if (!mesh->subdomainSection) {
1019:     PetscSection section;
1020:     PetscSF      sf;

1022:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1023:     DMGetDefaultSection(dm,&section);
1024:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1025:     PetscSFDestroy(&sf);
1026:   }
1027:   *subsection = mesh->subdomainSection;
1028:   return(0);
1029: }

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

1036:   Not collective

1038:   Input Parameter:
1039: . mesh - The DMPlex

1041:   Output Parameters:
1042: + pStart - The first mesh point
1043: - pEnd   - The upper bound for mesh points

1045:   Level: beginner

1047: .seealso: DMPlexCreate(), DMPlexSetChart()
1048: @*/
1049: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1050: {
1051:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1056:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1057:   return(0);
1058: }

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

1065:   Not collective

1067:   Input Parameters:
1068: + mesh - The DMPlex
1069: . pStart - The first mesh point
1070: - pEnd   - The upper bound for mesh points

1072:   Output Parameters:

1074:   Level: beginner

1076: .seealso: DMPlexCreate(), DMPlexGetChart()
1077: @*/
1078: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1079: {
1080:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1085:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1086:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1087:   return(0);
1088: }

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

1095:   Not collective

1097:   Input Parameters:
1098: + mesh - The DMPlex
1099: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1101:   Output Parameter:
1102: . size - The cone size for point p

1104:   Level: beginner

1106: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1107: @*/
1108: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1109: {
1110:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1116:   PetscSectionGetDof(mesh->coneSection, p, size);
1117:   return(0);
1118: }

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

1125:   Not collective

1127:   Input Parameters:
1128: + mesh - The DMPlex
1129: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1130: - size - The cone size for point p

1132:   Output Parameter:

1134:   Note:
1135:   This should be called after DMPlexSetChart().

1137:   Level: beginner

1139: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1140: @*/
1141: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1142: {
1143:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1150:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1151:   return(0);
1152: }

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

1159:   Not collective

1161:   Input Parameters:
1162: + mesh - The DMPlex
1163: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1164: - size - The additional cone size for point p

1166:   Output Parameter:

1168:   Note:
1169:   This should be called after DMPlexSetChart().

1171:   Level: beginner

1173: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1174: @*/
1175: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1176: {
1177:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1178:   PetscInt       csize;

1183:   PetscSectionAddDof(mesh->coneSection, p, size);
1184:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1186:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1187:   return(0);
1188: }

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

1195:   Not collective

1197:   Input Parameters:
1198: + mesh - The DMPlex
1199: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1204:   Level: beginner

1206:   Fortran Notes:
1207:   Since it returns an array, this routine is only available in Fortran 90, and you must
1208:   include petsc.h90 in your code.

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

1212: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1213: @*/
1214: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1215: {
1216:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1217:   PetscInt       off;

1223:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1224:   *cone = &mesh->cones[off];
1225:   return(0);
1226: }

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

1233:   Not collective

1235:   Input Parameters:
1236: + mesh - The DMPlex
1237: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1238: - cone - An array of points which are on the in-edges for point p

1240:   Output Parameter:

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

1245:   Level: beginner

1247: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1248: @*/
1249: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1250: {
1251:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1252:   PetscInt       pStart, pEnd;
1253:   PetscInt       dof, off, c;

1258:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1259:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1261:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1262:   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);
1263:   for (c = 0; c < dof; ++c) {
1264:     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);
1265:     mesh->cones[off+c] = cone[c];
1266:   }
1267:   return(0);
1268: }

1272: /*@C
1273:   DMPlexGetConeOrientation - Return the orientations 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()

1281:   Output Parameter:
1282: . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1283:                     integer giving the prescription for cone traversal. If it is negative, the cone is
1284:                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1285:                     the index of the cone point on which to start.

1287:   Level: beginner

1289:   Fortran Notes:
1290:   Since it returns an array, this routine is only available in Fortran 90, and you must
1291:   include petsc.h90 in your code.

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

1295: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1296: @*/
1297: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1298: {
1299:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1300:   PetscInt       off;

1305: #if defined(PETSC_USE_DEBUG)
1306:   {
1307:     PetscInt dof;
1308:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1310:   }
1311: #endif
1312:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1314:   *coneOrientation = &mesh->coneOrientations[off];
1315:   return(0);
1316: }

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

1323:   Not collective

1325:   Input Parameters:
1326: + mesh - The DMPlex
1327: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1328: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1329:                     integer giving the prescription for cone traversal. If it is negative, the cone is
1330:                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1331:                     the index of the cone point on which to start.

1333:   Output Parameter:

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

1338:   Level: beginner

1340: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1341: @*/
1342: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1343: {
1344:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1345:   PetscInt       pStart, pEnd;
1346:   PetscInt       dof, off, c;

1351:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1352:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1354:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1355:   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);
1356:   for (c = 0; c < dof; ++c) {
1357:     PetscInt cdof, o = coneOrientation[c];

1359:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1360:     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);
1361:     mesh->coneOrientations[off+c] = o;
1362:   }
1363:   return(0);
1364: }

1368: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1369: {
1370:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1371:   PetscInt       pStart, pEnd;
1372:   PetscInt       dof, off;

1377:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1378:   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);
1379:   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);
1380:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1381:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1382:   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);
1383:   mesh->cones[off+conePos] = conePoint;
1384:   return(0);
1385: }

1389: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1390: {
1391:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1392:   PetscInt       pStart, pEnd;
1393:   PetscInt       dof, off;

1398:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1399:   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);
1400:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1401:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1402:   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);
1403:   mesh->coneOrientations[off+conePos] = coneOrientation;
1404:   return(0);
1405: }

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

1412:   Not collective

1414:   Input Parameters:
1415: + mesh - The DMPlex
1416: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1418:   Output Parameter:
1419: . size - The support size for point p

1421:   Level: beginner

1423: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1424: @*/
1425: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1426: {
1427:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1433:   PetscSectionGetDof(mesh->supportSection, p, size);
1434:   return(0);
1435: }

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

1442:   Not collective

1444:   Input Parameters:
1445: + mesh - The DMPlex
1446: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1447: - size - The support size for point p

1449:   Output Parameter:

1451:   Note:
1452:   This should be called after DMPlexSetChart().

1454:   Level: beginner

1456: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1457: @*/
1458: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1459: {
1460:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1467:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1468:   return(0);
1469: }

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

1476:   Not collective

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

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

1485:   Level: beginner

1487:   Fortran Notes:
1488:   Since it returns an array, this routine is only available in Fortran 90, and you must
1489:   include petsc.h90 in your code.

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

1493: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1494: @*/
1495: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1496: {
1497:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1498:   PetscInt       off;

1504:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1505:   *support = &mesh->supports[off];
1506:   return(0);
1507: }

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

1514:   Not collective

1516:   Input Parameters:
1517: + mesh - The DMPlex
1518: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1519: - support - An array of points which are on the in-edges for point p

1521:   Output Parameter:

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

1526:   Level: beginner

1528: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1529: @*/
1530: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1531: {
1532:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1533:   PetscInt       pStart, pEnd;
1534:   PetscInt       dof, off, c;

1539:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1540:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1542:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1543:   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);
1544:   for (c = 0; c < dof; ++c) {
1545:     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);
1546:     mesh->supports[off+c] = support[c];
1547:   }
1548:   return(0);
1549: }

1553: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1554: {
1555:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1556:   PetscInt       pStart, pEnd;
1557:   PetscInt       dof, off;

1562:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1563:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1564:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1565:   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);
1566:   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);
1567:   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);
1568:   mesh->supports[off+supportPos] = supportPoint;
1569:   return(0);
1570: }

1574: /*@C
1575:   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG

1577:   Not collective

1579:   Input Parameters:
1580: + mesh - The DMPlex
1581: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1582: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1583: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

1585:   Output Parameters:
1586: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1587: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]

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

1592:   Fortran Notes:
1593:   Since it returns an array, this routine is only available in Fortran 90, and you must
1594:   include petsc.h90 in your code.

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

1598:   Level: beginner

1600: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1601: @*/
1602: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1603: {
1604:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1605:   PetscInt       *closure, *fifo;
1606:   const PetscInt *tmp = NULL, *tmpO = NULL;
1607:   PetscInt        tmpSize, t;
1608:   PetscInt        depth       = 0, maxSize;
1609:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1610:   PetscErrorCode  ierr;

1614:   DMPlexGetDepth(dm, &depth);
1615:   /* This is only 1-level */
1616:   if (useCone) {
1617:     DMPlexGetConeSize(dm, p, &tmpSize);
1618:     DMPlexGetCone(dm, p, &tmp);
1619:     DMPlexGetConeOrientation(dm, p, &tmpO);
1620:   } else {
1621:     DMPlexGetSupportSize(dm, p, &tmpSize);
1622:     DMPlexGetSupport(dm, p, &tmp);
1623:   }
1624:   if (depth == 1) {
1625:     if (*points) {
1626:       closure = *points;
1627:     } else {
1628:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1629:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1630:     }
1631:     closure[0] = p; closure[1] = 0;
1632:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1633:       closure[closureSize]   = tmp[t];
1634:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1635:     }
1636:     if (numPoints) *numPoints = closureSize/2;
1637:     if (points)    *points    = closure;
1638:     return(0);
1639:   }
1640:   {
1641:     PetscInt c, coneSeries, s,supportSeries;

1643:     c = mesh->maxConeSize;
1644:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1645:     s = mesh->maxSupportSize;
1646:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1647:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1648:   }
1649:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1650:   if (*points) {
1651:     closure = *points;
1652:   } else {
1653:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1654:   }
1655:   closure[0] = p; closure[1] = 0;
1656:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1657:     const PetscInt cp = tmp[t];
1658:     const PetscInt co = tmpO ? tmpO[t] : 0;

1660:     closure[closureSize]   = cp;
1661:     closure[closureSize+1] = co;
1662:     fifo[fifoSize]         = cp;
1663:     fifo[fifoSize+1]       = co;
1664:   }
1665:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1666:   while (fifoSize - fifoStart) {
1667:     const PetscInt q   = fifo[fifoStart];
1668:     const PetscInt o   = fifo[fifoStart+1];
1669:     const PetscInt rev = o >= 0 ? 0 : 1;
1670:     const PetscInt off = rev ? -(o+1) : o;

1672:     if (useCone) {
1673:       DMPlexGetConeSize(dm, q, &tmpSize);
1674:       DMPlexGetCone(dm, q, &tmp);
1675:       DMPlexGetConeOrientation(dm, q, &tmpO);
1676:     } else {
1677:       DMPlexGetSupportSize(dm, q, &tmpSize);
1678:       DMPlexGetSupport(dm, q, &tmp);
1679:       tmpO = NULL;
1680:     }
1681:     for (t = 0; t < tmpSize; ++t) {
1682:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1683:       const PetscInt cp = tmp[i];
1684:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1685:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1686:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1687:       PetscInt       co = tmpO ? tmpO[i] : 0;
1688:       PetscInt       c;

1690:       if (rev) {
1691:         PetscInt childSize, coff;
1692:         DMPlexGetConeSize(dm, cp, &childSize);
1693:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1694:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1695:       }
1696:       /* Check for duplicate */
1697:       for (c = 0; c < closureSize; c += 2) {
1698:         if (closure[c] == cp) break;
1699:       }
1700:       if (c == closureSize) {
1701:         closure[closureSize]   = cp;
1702:         closure[closureSize+1] = co;
1703:         fifo[fifoSize]         = cp;
1704:         fifo[fifoSize+1]       = co;
1705:         closureSize           += 2;
1706:         fifoSize              += 2;
1707:       }
1708:     }
1709:     fifoStart += 2;
1710:   }
1711:   if (numPoints) *numPoints = closureSize/2;
1712:   if (points)    *points    = closure;
1713:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1714:   return(0);
1715: }

1719: /*@C
1720:   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

1722:   Not collective

1724:   Input Parameters:
1725: + mesh - The DMPlex
1726: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1727: . orientation - The orientation of the point
1728: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1729: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

1731:   Output Parameters:
1732: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1733: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]

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

1738:   Fortran Notes:
1739:   Since it returns an array, this routine is only available in Fortran 90, and you must
1740:   include petsc.h90 in your code.

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

1744:   Level: beginner

1746: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1747: @*/
1748: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1749: {
1750:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1751:   PetscInt       *closure, *fifo;
1752:   const PetscInt *tmp = NULL, *tmpO = NULL;
1753:   PetscInt        tmpSize, t;
1754:   PetscInt        depth       = 0, maxSize;
1755:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1756:   PetscErrorCode  ierr;

1760:   DMPlexGetDepth(dm, &depth);
1761:   /* This is only 1-level */
1762:   if (useCone) {
1763:     DMPlexGetConeSize(dm, p, &tmpSize);
1764:     DMPlexGetCone(dm, p, &tmp);
1765:     DMPlexGetConeOrientation(dm, p, &tmpO);
1766:   } else {
1767:     DMPlexGetSupportSize(dm, p, &tmpSize);
1768:     DMPlexGetSupport(dm, p, &tmp);
1769:   }
1770:   if (depth == 1) {
1771:     if (*points) {
1772:       closure = *points;
1773:     } else {
1774:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1775:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1776:     }
1777:     closure[0] = p; closure[1] = ornt;
1778:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1779:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1780:       closure[closureSize]   = tmp[i];
1781:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1782:     }
1783:     if (numPoints) *numPoints = closureSize/2;
1784:     if (points)    *points    = closure;
1785:     return(0);
1786:   }
1787:   {
1788:     PetscInt c, coneSeries, s,supportSeries;

1790:     c = mesh->maxConeSize;
1791:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1792:     s = mesh->maxSupportSize;
1793:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1794:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1795:   }
1796:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1797:   if (*points) {
1798:     closure = *points;
1799:   } else {
1800:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1801:   }
1802:   closure[0] = p; closure[1] = ornt;
1803:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1804:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1805:     const PetscInt cp = tmp[i];
1806:     PetscInt       co = tmpO ? tmpO[i] : 0;

1808:     if (ornt < 0) {
1809:       PetscInt childSize, coff;
1810:       DMPlexGetConeSize(dm, cp, &childSize);
1811:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
1812:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1813:     }
1814:     closure[closureSize]   = cp;
1815:     closure[closureSize+1] = co;
1816:     fifo[fifoSize]         = cp;
1817:     fifo[fifoSize+1]       = co;
1818:   }
1819:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1820:   while (fifoSize - fifoStart) {
1821:     const PetscInt q   = fifo[fifoStart];
1822:     const PetscInt o   = fifo[fifoStart+1];
1823:     const PetscInt rev = o >= 0 ? 0 : 1;
1824:     const PetscInt off = rev ? -(o+1) : o;

1826:     if (useCone) {
1827:       DMPlexGetConeSize(dm, q, &tmpSize);
1828:       DMPlexGetCone(dm, q, &tmp);
1829:       DMPlexGetConeOrientation(dm, q, &tmpO);
1830:     } else {
1831:       DMPlexGetSupportSize(dm, q, &tmpSize);
1832:       DMPlexGetSupport(dm, q, &tmp);
1833:       tmpO = NULL;
1834:     }
1835:     for (t = 0; t < tmpSize; ++t) {
1836:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1837:       const PetscInt cp = tmp[i];
1838:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1839:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1840:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1841:       PetscInt       co = tmpO ? tmpO[i] : 0;
1842:       PetscInt       c;

1844:       if (rev) {
1845:         PetscInt childSize, coff;
1846:         DMPlexGetConeSize(dm, cp, &childSize);
1847:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1848:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1849:       }
1850:       /* Check for duplicate */
1851:       for (c = 0; c < closureSize; c += 2) {
1852:         if (closure[c] == cp) break;
1853:       }
1854:       if (c == closureSize) {
1855:         closure[closureSize]   = cp;
1856:         closure[closureSize+1] = co;
1857:         fifo[fifoSize]         = cp;
1858:         fifo[fifoSize+1]       = co;
1859:         closureSize           += 2;
1860:         fifoSize              += 2;
1861:       }
1862:     }
1863:     fifoStart += 2;
1864:   }
1865:   if (numPoints) *numPoints = closureSize/2;
1866:   if (points)    *points    = closure;
1867:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1868:   return(0);
1869: }

1873: /*@C
1874:   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG

1876:   Not collective

1878:   Input Parameters:
1879: + mesh - The DMPlex
1880: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1881: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1882: . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
1883: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit

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

1888:   Fortran Notes:
1889:   Since it returns an array, this routine is only available in Fortran 90, and you must
1890:   include petsc.h90 in your code.

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

1894:   Level: beginner

1896: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1897: @*/
1898: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1899: {

1906:   DMRestoreWorkArray(dm, 0, PETSC_INT, points);
1907:   if (numPoints) *numPoints = 0;
1908:   return(0);
1909: }

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

1916:   Not collective

1918:   Input Parameter:
1919: . mesh - The DMPlex

1921:   Output Parameters:
1922: + maxConeSize - The maximum number of in-edges
1923: - maxSupportSize - The maximum number of out-edges

1925:   Level: beginner

1927: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1928: @*/
1929: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1930: {
1931:   DM_Plex *mesh = (DM_Plex*) dm->data;

1935:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1936:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1937:   return(0);
1938: }

1942: PetscErrorCode DMSetUp_Plex(DM dm)
1943: {
1944:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1945:   PetscInt       size;

1950:   PetscSectionSetUp(mesh->coneSection);
1951:   PetscSectionGetStorageSize(mesh->coneSection, &size);
1952:   PetscMalloc1(size, &mesh->cones);
1953:   PetscCalloc1(size, &mesh->coneOrientations);
1954:   if (mesh->maxSupportSize) {
1955:     PetscSectionSetUp(mesh->supportSection);
1956:     PetscSectionGetStorageSize(mesh->supportSection, &size);
1957:     PetscMalloc1(size, &mesh->supports);
1958:   }
1959:   return(0);
1960: }

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

1969:   if (subdm) {DMClone(dm, subdm);}
1970:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
1971:   return(0);
1972: }

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

1979:   Not collective

1981:   Input Parameter:
1982: . mesh - The DMPlex

1984:   Output Parameter:

1986:   Note:
1987:   This should be called after all calls to DMPlexSetCone()

1989:   Level: beginner

1991: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1992: @*/
1993: PetscErrorCode DMPlexSymmetrize(DM dm)
1994: {
1995:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1996:   PetscInt      *offsets;
1997:   PetscInt       supportSize;
1998:   PetscInt       pStart, pEnd, p;

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

2009:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2010:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2011:     for (c = off; c < off+dof; ++c) {
2012:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2013:     }
2014:   }
2015:   for (p = pStart; p < pEnd; ++p) {
2016:     PetscInt dof;

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

2020:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2021:   }
2022:   PetscSectionSetUp(mesh->supportSection);
2023:   /* Calculate supports */
2024:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2025:   PetscMalloc1(supportSize, &mesh->supports);
2026:   PetscCalloc1(pEnd - pStart, &offsets);
2027:   for (p = pStart; p < pEnd; ++p) {
2028:     PetscInt dof, off, c;

2030:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2031:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2032:     for (c = off; c < off+dof; ++c) {
2033:       const PetscInt q = mesh->cones[c];
2034:       PetscInt       offS;

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

2038:       mesh->supports[offS+offsets[q]] = p;
2039:       ++offsets[q];
2040:     }
2041:   }
2042:   PetscFree(offsets);
2043:   return(0);
2044: }

2048: /*@
2049:   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2050:   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2051:   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2052:   the DAG.

2054:   Collective on dm

2056:   Input Parameter:
2057: . mesh - The DMPlex

2059:   Output Parameter:

2061:   Notes:
2062:   Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
2063:   1 for edges, and so on.  The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2064:   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
2065:   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.

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

2069:   Level: beginner

2071: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2072: @*/
2073: PetscErrorCode DMPlexStratify(DM dm)
2074: {
2075:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2076:   DMLabel        label;
2077:   PetscInt       pStart, pEnd, p;
2078:   PetscInt       numRoots = 0, numLeaves = 0;

2083:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2084:   /* Calculate depth */
2085:   DMPlexGetChart(dm, &pStart, &pEnd);
2086:   DMCreateLabel(dm, "depth");
2087:   DMPlexGetDepthLabel(dm, &label);
2088:   /* Initialize roots and count leaves */
2089:   for (p = pStart; p < pEnd; ++p) {
2090:     PetscInt coneSize, supportSize;

2092:     DMPlexGetConeSize(dm, p, &coneSize);
2093:     DMPlexGetSupportSize(dm, p, &supportSize);
2094:     if (!coneSize && supportSize) {
2095:       ++numRoots;
2096:       DMLabelSetValue(label, p, 0);
2097:     } else if (!supportSize && coneSize) {
2098:       ++numLeaves;
2099:     } else if (!supportSize && !coneSize) {
2100:       /* Isolated points */
2101:       DMLabelSetValue(label, p, 0);
2102:     }
2103:   }
2104:   if (numRoots + numLeaves == (pEnd - pStart)) {
2105:     for (p = pStart; p < pEnd; ++p) {
2106:       PetscInt coneSize, supportSize;

2108:       DMPlexGetConeSize(dm, p, &coneSize);
2109:       DMPlexGetSupportSize(dm, p, &supportSize);
2110:       if (!supportSize && coneSize) {
2111:         DMLabelSetValue(label, p, 1);
2112:       }
2113:     }
2114:   } else {
2115:     IS       pointIS;
2116:     PetscInt numPoints = 0, level = 0;

2118:     DMLabelGetStratumIS(label, level, &pointIS);
2119:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2120:     while (numPoints) {
2121:       const PetscInt *points;
2122:       const PetscInt  newLevel = level+1;

2124:       ISGetIndices(pointIS, &points);
2125:       for (p = 0; p < numPoints; ++p) {
2126:         const PetscInt  point = points[p];
2127:         const PetscInt *support;
2128:         PetscInt        supportSize, s;

2130:         DMPlexGetSupportSize(dm, point, &supportSize);
2131:         DMPlexGetSupport(dm, point, &support);
2132:         for (s = 0; s < supportSize; ++s) {
2133:           DMLabelSetValue(label, support[s], newLevel);
2134:         }
2135:       }
2136:       ISRestoreIndices(pointIS, &points);
2137:       ++level;
2138:       ISDestroy(&pointIS);
2139:       DMLabelGetStratumIS(label, level, &pointIS);
2140:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2141:       else         {numPoints = 0;}
2142:     }
2143:     ISDestroy(&pointIS);
2144:   }
2145:   { /* just in case there is an empty process */
2146:     PetscInt numValues, maxValues = 0, v;

2148:     DMLabelGetNumValues(label,&numValues);
2149:     for (v = 0; v < numValues; v++) {
2150:       IS pointIS;

2152:       DMLabelGetStratumIS(label, v, &pointIS);
2153:       if (pointIS) {
2154:         PetscInt  min, max, numPoints;
2155:         PetscInt  start;
2156:         PetscBool contig;

2158:         ISGetLocalSize(pointIS, &numPoints);
2159:         ISGetMinMax(pointIS, &min, &max);
2160:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2161:         if (start == 0 && contig) {
2162:           ISDestroy(&pointIS);
2163:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2164:           DMLabelSetStratumIS(label, v, pointIS);
2165:         }
2166:       }
2167:       ISDestroy(&pointIS);
2168:     }
2169:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2170:     for (v = numValues; v < maxValues; v++) {
2171:       DMLabelAddStratum(label,v);
2172:     }
2173:   }

2175:   DMLabelGetState(label, &mesh->depthState);
2176:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2177:   return(0);
2178: }

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

2185:   Not Collective

2187:   Input Parameters:
2188: + dm - The DMPlex object
2189: . numPoints - The number of input points for the join
2190: - points - The input points

2192:   Output Parameters:
2193: + numCoveredPoints - The number of points in the join
2194: - coveredPoints - The points in the join

2196:   Level: intermediate

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

2200:   Fortran Notes:
2201:   Since it returns an array, this routine is only available in Fortran 90, and you must
2202:   include petsc.h90 in your code.

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

2206: .keywords: mesh
2207: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2208: @*/
2209: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2210: {
2211:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2212:   PetscInt      *join[2];
2213:   PetscInt       joinSize, i = 0;
2214:   PetscInt       dof, off, p, c, m;

2222:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
2223:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
2224:   /* Copy in support of first point */
2225:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2226:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2227:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2228:     join[i][joinSize] = mesh->supports[off+joinSize];
2229:   }
2230:   /* Check each successive support */
2231:   for (p = 1; p < numPoints; ++p) {
2232:     PetscInt newJoinSize = 0;

2234:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2235:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2236:     for (c = 0; c < dof; ++c) {
2237:       const PetscInt point = mesh->supports[off+c];

2239:       for (m = 0; m < joinSize; ++m) {
2240:         if (point == join[i][m]) {
2241:           join[1-i][newJoinSize++] = point;
2242:           break;
2243:         }
2244:       }
2245:     }
2246:     joinSize = newJoinSize;
2247:     i        = 1-i;
2248:   }
2249:   *numCoveredPoints = joinSize;
2250:   *coveredPoints    = join[i];
2251:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2252:   return(0);
2253: }

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

2260:   Not Collective

2262:   Input Parameters:
2263: + dm - The DMPlex object
2264: . numPoints - The number of input points for the join
2265: - points - The input points

2267:   Output Parameters:
2268: + numCoveredPoints - The number of points in the join
2269: - coveredPoints - The points in the join

2271:   Fortran Notes:
2272:   Since it returns an array, this routine is only available in Fortran 90, and you must
2273:   include petsc.h90 in your code.

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

2277:   Level: intermediate

2279: .keywords: mesh
2280: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2281: @*/
2282: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2283: {

2291:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2292:   if (numCoveredPoints) *numCoveredPoints = 0;
2293:   return(0);
2294: }

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

2301:   Not Collective

2303:   Input Parameters:
2304: + dm - The DMPlex object
2305: . numPoints - The number of input points for the join
2306: - points - The input points

2308:   Output Parameters:
2309: + numCoveredPoints - The number of points in the join
2310: - coveredPoints - The points in the join

2312:   Fortran Notes:
2313:   Since it returns an array, this routine is only available in Fortran 90, and you must
2314:   include petsc.h90 in your code.

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

2318:   Level: intermediate

2320: .keywords: mesh
2321: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2322: @*/
2323: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2324: {
2325:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2326:   PetscInt      *offsets, **closures;
2327:   PetscInt      *join[2];
2328:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2329:   PetscInt       p, d, c, m, ms;


2338:   DMPlexGetDepth(dm, &depth);
2339:   PetscCalloc1(numPoints, &closures);
2340:   DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2341:   ms      = mesh->maxSupportSize;
2342:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2343:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
2344:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);

2346:   for (p = 0; p < numPoints; ++p) {
2347:     PetscInt closureSize;

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

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

2355:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2356:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2357:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2358:           offsets[p*(depth+2)+d+1] = i;
2359:           break;
2360:         }
2361:       }
2362:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2363:     }
2364:     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);
2365:   }
2366:   for (d = 0; d < depth+1; ++d) {
2367:     PetscInt dof;

2369:     /* Copy in support of first point */
2370:     dof = offsets[d+1] - offsets[d];
2371:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2372:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2373:     }
2374:     /* Check each successive cone */
2375:     for (p = 1; p < numPoints && joinSize; ++p) {
2376:       PetscInt newJoinSize = 0;

2378:       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2379:       for (c = 0; c < dof; ++c) {
2380:         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];

2382:         for (m = 0; m < joinSize; ++m) {
2383:           if (point == join[i][m]) {
2384:             join[1-i][newJoinSize++] = point;
2385:             break;
2386:           }
2387:         }
2388:       }
2389:       joinSize = newJoinSize;
2390:       i        = 1-i;
2391:     }
2392:     if (joinSize) break;
2393:   }
2394:   *numCoveredPoints = joinSize;
2395:   *coveredPoints    = join[i];
2396:   for (p = 0; p < numPoints; ++p) {
2397:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2398:   }
2399:   PetscFree(closures);
2400:   DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2401:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2402:   return(0);
2403: }

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

2410:   Not Collective

2412:   Input Parameters:
2413: + dm - The DMPlex object
2414: . numPoints - The number of input points for the meet
2415: - points - The input points

2417:   Output Parameters:
2418: + numCoveredPoints - The number of points in the meet
2419: - coveredPoints - The points in the meet

2421:   Level: intermediate

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

2425:   Fortran Notes:
2426:   Since it returns an array, this routine is only available in Fortran 90, and you must
2427:   include petsc.h90 in your code.

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

2431: .keywords: mesh
2432: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2433: @*/
2434: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2435: {
2436:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2437:   PetscInt      *meet[2];
2438:   PetscInt       meetSize, i = 0;
2439:   PetscInt       dof, off, p, c, m;

2447:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
2448:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
2449:   /* Copy in cone of first point */
2450:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2451:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2452:   for (meetSize = 0; meetSize < dof; ++meetSize) {
2453:     meet[i][meetSize] = mesh->cones[off+meetSize];
2454:   }
2455:   /* Check each successive cone */
2456:   for (p = 1; p < numPoints; ++p) {
2457:     PetscInt newMeetSize = 0;

2459:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2460:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2461:     for (c = 0; c < dof; ++c) {
2462:       const PetscInt point = mesh->cones[off+c];

2464:       for (m = 0; m < meetSize; ++m) {
2465:         if (point == meet[i][m]) {
2466:           meet[1-i][newMeetSize++] = point;
2467:           break;
2468:         }
2469:       }
2470:     }
2471:     meetSize = newMeetSize;
2472:     i        = 1-i;
2473:   }
2474:   *numCoveringPoints = meetSize;
2475:   *coveringPoints    = meet[i];
2476:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2477:   return(0);
2478: }

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

2485:   Not Collective

2487:   Input Parameters:
2488: + dm - The DMPlex object
2489: . numPoints - The number of input points for the meet
2490: - points - The input points

2492:   Output Parameters:
2493: + numCoveredPoints - The number of points in the meet
2494: - coveredPoints - The points in the meet

2496:   Level: intermediate

2498:   Fortran Notes:
2499:   Since it returns an array, this routine is only available in Fortran 90, and you must
2500:   include petsc.h90 in your code.

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

2504: .keywords: mesh
2505: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2506: @*/
2507: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2508: {

2516:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2517:   if (numCoveredPoints) *numCoveredPoints = 0;
2518:   return(0);
2519: }

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

2526:   Not Collective

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

2533:   Output Parameters:
2534: + numCoveredPoints - The number of points in the meet
2535: - coveredPoints - The points in the meet

2537:   Level: intermediate

2539:   Fortran Notes:
2540:   Since it returns an array, this routine is only available in Fortran 90, and you must
2541:   include petsc.h90 in your code.

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

2545: .keywords: mesh
2546: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2547: @*/
2548: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2549: {
2550:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2551:   PetscInt      *offsets, **closures;
2552:   PetscInt      *meet[2];
2553:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2554:   PetscInt       p, h, c, m, mc;


2563:   DMPlexGetDepth(dm, &height);
2564:   PetscMalloc1(numPoints, &closures);
2565:   DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2566:   mc      = mesh->maxConeSize;
2567:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2568:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
2569:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);

2571:   for (p = 0; p < numPoints; ++p) {
2572:     PetscInt closureSize;

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

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

2580:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2581:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2582:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2583:           offsets[p*(height+2)+h+1] = i;
2584:           break;
2585:         }
2586:       }
2587:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2588:     }
2589:     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);
2590:   }
2591:   for (h = 0; h < height+1; ++h) {
2592:     PetscInt dof;

2594:     /* Copy in cone of first point */
2595:     dof = offsets[h+1] - offsets[h];
2596:     for (meetSize = 0; meetSize < dof; ++meetSize) {
2597:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2598:     }
2599:     /* Check each successive cone */
2600:     for (p = 1; p < numPoints && meetSize; ++p) {
2601:       PetscInt newMeetSize = 0;

2603:       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2604:       for (c = 0; c < dof; ++c) {
2605:         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];

2607:         for (m = 0; m < meetSize; ++m) {
2608:           if (point == meet[i][m]) {
2609:             meet[1-i][newMeetSize++] = point;
2610:             break;
2611:           }
2612:         }
2613:       }
2614:       meetSize = newMeetSize;
2615:       i        = 1-i;
2616:     }
2617:     if (meetSize) break;
2618:   }
2619:   *numCoveredPoints = meetSize;
2620:   *coveredPoints    = meet[i];
2621:   for (p = 0; p < numPoints; ++p) {
2622:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2623:   }
2624:   PetscFree(closures);
2625:   DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2626:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2627:   return(0);
2628: }

2632: /*@C
2633:   DMPlexEqual - Determine if two DMs have the same topology

2635:   Not Collective

2637:   Input Parameters:
2638: + dmA - A DMPlex object
2639: - dmB - A DMPlex object

2641:   Output Parameters:
2642: . equal - PETSC_TRUE if the topologies are identical

2644:   Level: intermediate

2646:   Notes:
2647:   We are not solving graph isomorphism, so we do not permutation.

2649: .keywords: mesh
2650: .seealso: DMPlexGetCone()
2651: @*/
2652: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2653: {
2654:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


2662:   *equal = PETSC_FALSE;
2663:   DMPlexGetDepth(dmA, &depth);
2664:   DMPlexGetDepth(dmB, &depthB);
2665:   if (depth != depthB) return(0);
2666:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2667:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2668:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2669:   for (p = pStart; p < pEnd; ++p) {
2670:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2671:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

2673:     DMPlexGetConeSize(dmA, p, &coneSize);
2674:     DMPlexGetCone(dmA, p, &cone);
2675:     DMPlexGetConeOrientation(dmA, p, &ornt);
2676:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2677:     DMPlexGetCone(dmB, p, &coneB);
2678:     DMPlexGetConeOrientation(dmB, p, &orntB);
2679:     if (coneSize != coneSizeB) return(0);
2680:     for (c = 0; c < coneSize; ++c) {
2681:       if (cone[c] != coneB[c]) return(0);
2682:       if (ornt[c] != orntB[c]) return(0);
2683:     }
2684:     DMPlexGetSupportSize(dmA, p, &supportSize);
2685:     DMPlexGetSupport(dmA, p, &support);
2686:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2687:     DMPlexGetSupport(dmB, p, &supportB);
2688:     if (supportSize != supportSizeB) return(0);
2689:     for (s = 0; s < supportSize; ++s) {
2690:       if (support[s] != supportB[s]) return(0);
2691:     }
2692:   }
2693:   *equal = PETSC_TRUE;
2694:   return(0);
2695: }

2699: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2700: {
2701:   MPI_Comm       comm;

2705:   PetscObjectGetComm((PetscObject)dm,&comm);
2707:   switch (cellDim) {
2708:   case 0:
2709:     *numFaceVertices = 0;
2710:     break;
2711:   case 1:
2712:     *numFaceVertices = 1;
2713:     break;
2714:   case 2:
2715:     switch (numCorners) {
2716:     case 3: /* triangle */
2717:       *numFaceVertices = 2; /* Edge has 2 vertices */
2718:       break;
2719:     case 4: /* quadrilateral */
2720:       *numFaceVertices = 2; /* Edge has 2 vertices */
2721:       break;
2722:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2723:       *numFaceVertices = 3; /* Edge has 3 vertices */
2724:       break;
2725:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2726:       *numFaceVertices = 3; /* Edge has 3 vertices */
2727:       break;
2728:     default:
2729:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2730:     }
2731:     break;
2732:   case 3:
2733:     switch (numCorners) {
2734:     case 4: /* tetradehdron */
2735:       *numFaceVertices = 3; /* Face has 3 vertices */
2736:       break;
2737:     case 6: /* tet cohesive cells */
2738:       *numFaceVertices = 4; /* Face has 4 vertices */
2739:       break;
2740:     case 8: /* hexahedron */
2741:       *numFaceVertices = 4; /* Face has 4 vertices */
2742:       break;
2743:     case 9: /* tet cohesive Lagrange cells */
2744:       *numFaceVertices = 6; /* Face has 6 vertices */
2745:       break;
2746:     case 10: /* quadratic tetrahedron */
2747:       *numFaceVertices = 6; /* Face has 6 vertices */
2748:       break;
2749:     case 12: /* hex cohesive Lagrange cells */
2750:       *numFaceVertices = 6; /* Face has 6 vertices */
2751:       break;
2752:     case 18: /* quadratic tet cohesive Lagrange cells */
2753:       *numFaceVertices = 6; /* Face has 6 vertices */
2754:       break;
2755:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2756:       *numFaceVertices = 9; /* Face has 9 vertices */
2757:       break;
2758:     default:
2759:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2760:     }
2761:     break;
2762:   default:
2763:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
2764:   }
2765:   return(0);
2766: }

2770: /*@
2771:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

2773:   Not Collective

2775:   Input Parameter:
2776: . dm    - The DMPlex object

2778:   Output Parameter:
2779: . depthLabel - The DMLabel recording point depth

2781:   Level: developer

2783: .keywords: mesh, points
2784: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2785: @*/
2786: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2787: {

2793:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
2794:   *depthLabel = dm->depthLabel;
2795:   return(0);
2796: }

2800: /*@
2801:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

2803:   Not Collective

2805:   Input Parameter:
2806: . dm    - The DMPlex object

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

2811:   Level: developer

2813: .keywords: mesh, points
2814: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2815: @*/
2816: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
2817: {
2818:   DMLabel        label;
2819:   PetscInt       d = 0;

2825:   DMPlexGetDepthLabel(dm, &label);
2826:   if (label) {DMLabelGetNumValues(label, &d);}
2827:   *depth = d-1;
2828:   return(0);
2829: }

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

2836:   Not Collective

2838:   Input Parameters:
2839: + dm           - The DMPlex object
2840: - stratumValue - The requested depth

2842:   Output Parameters:
2843: + start - The first point at this depth
2844: - end   - One beyond the last point at this depth

2846:   Level: developer

2848: .keywords: mesh, points
2849: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
2850: @*/
2851: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2852: {
2853:   DMLabel        label;
2854:   PetscInt       pStart, pEnd;

2861:   DMPlexGetChart(dm, &pStart, &pEnd);
2862:   if (pStart == pEnd) return(0);
2863:   if (stratumValue < 0) {
2864:     if (start) *start = pStart;
2865:     if (end)   *end   = pEnd;
2866:     return(0);
2867:   }
2868:   DMPlexGetDepthLabel(dm, &label);
2869:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2870:   DMLabelGetStratumBounds(label, stratumValue, start, end);
2871:   return(0);
2872: }

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

2879:   Not Collective

2881:   Input Parameters:
2882: + dm           - The DMPlex object
2883: - stratumValue - The requested height

2885:   Output Parameters:
2886: + start - The first point at this height
2887: - end   - One beyond the last point at this height

2889:   Level: developer

2891: .keywords: mesh, points
2892: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
2893: @*/
2894: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2895: {
2896:   DMLabel        label;
2897:   PetscInt       depth, pStart, pEnd;

2904:   DMPlexGetChart(dm, &pStart, &pEnd);
2905:   if (pStart == pEnd) return(0);
2906:   if (stratumValue < 0) {
2907:     if (start) *start = pStart;
2908:     if (end)   *end   = pEnd;
2909:     return(0);
2910:   }
2911:   DMPlexGetDepthLabel(dm, &label);
2912:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2913:   DMLabelGetNumValues(label, &depth);
2914:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
2915:   return(0);
2916: }

2920: /* Set the number of dof on each point and separate by fields */
2921: PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
2922: {
2923:   PetscInt      *pMax;
2924:   PetscInt       depth, pStart = 0, pEnd = 0;
2925:   PetscInt       Nf, p, d, dep, f;
2926:   PetscBool     *isFE;

2930:   PetscMalloc1(numFields, &isFE);
2931:   DMGetNumFields(dm, &Nf);
2932:   for (f = 0; f < numFields; ++f) {
2933:     PetscObject  obj;
2934:     PetscClassId id;

2936:     isFE[f] = PETSC_FALSE;
2937:     if (f >= Nf) continue;
2938:     DMGetField(dm, f, &obj);
2939:     PetscObjectGetClassId(obj, &id);
2940:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
2941:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2942:   }
2943:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
2944:   if (numFields > 0) {
2945:     PetscSectionSetNumFields(*section, numFields);
2946:     if (numComp) {
2947:       for (f = 0; f < numFields; ++f) {
2948:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
2949:       }
2950:     }
2951:   }
2952:   DMPlexGetChart(dm, &pStart, &pEnd);
2953:   PetscSectionSetChart(*section, pStart, pEnd);
2954:   DMPlexGetDepth(dm, &depth);
2955:   PetscMalloc1(depth+1,&pMax);
2956:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
2957:   for (dep = 0; dep <= depth; ++dep) {
2958:     d    = dim == depth ? dep : (!dep ? 0 : dim);
2959:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
2960:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
2961:     for (p = pStart; p < pEnd; ++p) {
2962:       PetscInt tot = 0;

2964:       for (f = 0; f < numFields; ++f) {
2965:         if (isFE[f] && p >= pMax[dep]) continue;
2966:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
2967:         tot += numDof[f*(dim+1)+d];
2968:       }
2969:       PetscSectionSetDof(*section, p, tot);
2970:     }
2971:   }
2972:   PetscFree(pMax);
2973:   PetscFree(isFE);
2974:   return(0);
2975: }

2979: /* Set the number of dof on each point and separate by fields
2980:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
2981: */
2982: PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
2983: {
2984:   PetscInt       numFields;
2985:   PetscInt       bc;
2986:   PetscSection   aSec;

2990:   PetscSectionGetNumFields(section, &numFields);
2991:   for (bc = 0; bc < numBC; ++bc) {
2992:     PetscInt        field = 0;
2993:     const PetscInt *comp;
2994:     const PetscInt *idx;
2995:     PetscInt        Nc = -1, n, i;

2997:     if (numFields) field = bcField[bc];
2998:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
2999:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3000:     ISGetLocalSize(bcPoints[bc], &n);
3001:     ISGetIndices(bcPoints[bc], &idx);
3002:     for (i = 0; i < n; ++i) {
3003:       const PetscInt p = idx[i];
3004:       PetscInt       numConst;

3006:       if (numFields) {
3007:         PetscSectionGetFieldDof(section, p, field, &numConst);
3008:       } else {
3009:         PetscSectionGetDof(section, p, &numConst);
3010:       }
3011:       /* If Nc < 0, constrain every dof on the point */
3012:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3013:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3014:       PetscSectionAddConstraintDof(section, p, numConst);
3015:     }
3016:     ISRestoreIndices(bcPoints[bc], &idx);
3017:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3018:   }
3019:   DMPlexGetAnchors(dm, &aSec, NULL);
3020:   if (aSec) {
3021:     PetscInt aStart, aEnd, a;

3023:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3024:     for (a = aStart; a < aEnd; a++) {
3025:       PetscInt dof, f;

3027:       PetscSectionGetDof(aSec, a, &dof);
3028:       if (dof) {
3029:         /* if there are point-to-point constraints, then all dofs are constrained */
3030:         PetscSectionGetDof(section, a, &dof);
3031:         PetscSectionSetConstraintDof(section, a, dof);
3032:         for (f = 0; f < numFields; f++) {
3033:           PetscSectionGetFieldDof(section, a, f, &dof);
3034:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3035:         }
3036:       }
3037:     }
3038:   }
3039:   return(0);
3040: }

3044: /* Set the constrained field indices on each point
3045:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3046: */
3047: PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3048: {
3049:   PetscSection   aSec;
3050:   PetscInt      *indices;
3051:   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;

3055:   PetscSectionGetNumFields(section, &numFields);
3056:   if (!numFields) return(0);
3057:   /* Initialize all field indices to -1 */
3058:   PetscSectionGetChart(section, &pStart, &pEnd);
3059:   PetscSectionGetMaxDof(section, &maxDof);
3060:   PetscMalloc1(maxDof, &indices);
3061:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3062:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3063:   /* Handle BC constraints */
3064:   for (bc = 0; bc < numBC; ++bc) {
3065:     const PetscInt  field = bcField[bc];
3066:     const PetscInt *comp, *idx;
3067:     PetscInt        Nc = -1, n, i;

3069:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3070:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3071:     ISGetLocalSize(bcPoints[bc], &n);
3072:     ISGetIndices(bcPoints[bc], &idx);
3073:     for (i = 0; i < n; ++i) {
3074:       const PetscInt  p = idx[i];
3075:       const PetscInt *find;
3076:       PetscInt        fcdof, c;

3078:       PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3079:       if (Nc < 0) {
3080:         for (d = 0; d < fcdof; ++d) indices[d] = d;
3081:       } else {
3082:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3083:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3084:         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
3085:         PetscSortInt(d+Nc, indices);
3086:         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
3087:       }
3088:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3089:     }
3090:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3091:     ISRestoreIndices(bcPoints[bc], &idx);
3092:   }
3093:   /* Handle anchors */
3094:   DMPlexGetAnchors(dm, &aSec, NULL);
3095:   if (aSec) {
3096:     PetscInt aStart, aEnd, a;

3098:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3099:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3100:     for (a = aStart; a < aEnd; a++) {
3101:       PetscInt dof, fdof, f;

3103:       PetscSectionGetDof(aSec, a, &dof);
3104:       if (dof) {
3105:         /* if there are point-to-point constraints, then all dofs are constrained */
3106:         for (f = 0; f < numFields; f++) {
3107:           PetscSectionGetFieldDof(section, a, f, &fdof);
3108:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3109:         }
3110:       }
3111:     }
3112:   }
3113:   PetscFree(indices);
3114:   return(0);
3115: }

3119: /* Set the constrained indices on each point */
3120: PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3121: {
3122:   PetscInt      *indices;
3123:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3127:   PetscSectionGetNumFields(section, &numFields);
3128:   PetscSectionGetMaxDof(section, &maxDof);
3129:   PetscSectionGetChart(section, &pStart, &pEnd);
3130:   PetscMalloc1(maxDof, &indices);
3131:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3132:   for (p = pStart; p < pEnd; ++p) {
3133:     PetscInt cdof, d;

3135:     PetscSectionGetConstraintDof(section, p, &cdof);
3136:     if (cdof) {
3137:       if (numFields) {
3138:         PetscInt numConst = 0, foff = 0;

3140:         for (f = 0; f < numFields; ++f) {
3141:           const PetscInt *find;
3142:           PetscInt        fcdof, fdof;

3144:           PetscSectionGetFieldDof(section, p, f, &fdof);
3145:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3146:           /* Change constraint numbering from field component to local dof number */
3147:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3148:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3149:           numConst += fcdof;
3150:           foff     += fdof;
3151:         }
3152:         if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
3153:       } else {
3154:         for (d = 0; d < cdof; ++d) indices[d] = d;
3155:       }
3156:       PetscSectionSetConstraintIndices(section, p, indices);
3157:     }
3158:   }
3159:   PetscFree(indices);
3160:   return(0);
3161: }

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

3168:   Not Collective

3170:   Input Parameters:
3171: + dm        - The DMPlex object
3172: . dim       - The spatial dimension of the problem
3173: . numFields - The number of fields in the problem
3174: . numComp   - An array of size numFields that holds the number of components for each field
3175: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3176: . numBC     - The number of boundary conditions
3177: . bcField   - An array of size numBC giving the field number for each boundry condition
3178: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3179: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3180: - perm      - Optional permutation of the chart, or NULL

3182:   Output Parameter:
3183: . section - The PetscSection object

3185:   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
3186:   number of dof for field 0 on each edge.

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

3190:   Level: developer

3192:   Fortran Notes:
3193:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3195: .keywords: mesh, elements
3196: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3197: @*/
3198: 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)
3199: {
3200:   PetscSection   aSec;

3204:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3205:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3206:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3207:   PetscSectionSetUp(*section);
3208:   DMPlexGetAnchors(dm,&aSec,NULL);
3209:   if (numBC || aSec) {
3210:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3211:     DMPlexCreateSectionBCIndices(dm, *section);
3212:   }
3213:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3214:   return(0);
3215: }

3219: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3220: {
3221:   PetscSection   section, s;
3222:   Mat            m;
3223:   PetscInt       maxHeight;

3227:   DMClone(dm, cdm);
3228:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3229:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3230:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3231:   DMSetDefaultSection(*cdm, section);
3232:   PetscSectionDestroy(&section);
3233:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3234:   MatCreate(PETSC_COMM_SELF, &m);
3235:   DMSetDefaultConstraints(*cdm, s, m);
3236:   PetscSectionDestroy(&s);
3237:   MatDestroy(&m);
3238:   return(0);
3239: }

3243: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3244: {
3245:   DM_Plex *mesh = (DM_Plex*) dm->data;

3249:   if (section) *section = mesh->coneSection;
3250:   return(0);
3251: }

3255: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3256: {
3257:   DM_Plex *mesh = (DM_Plex*) dm->data;

3261:   if (section) *section = mesh->supportSection;
3262:   return(0);
3263: }

3267: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3268: {
3269:   DM_Plex *mesh = (DM_Plex*) dm->data;

3273:   if (cones) *cones = mesh->cones;
3274:   return(0);
3275: }

3279: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3280: {
3281:   DM_Plex *mesh = (DM_Plex*) dm->data;

3285:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3286:   return(0);
3287: }

3289: /******************************** FEM Support **********************************/

3293: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section)
3294: {
3295:   PetscInt      *perm;
3296:   PetscInt       dim, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3300:   if (!section) {DMGetDefaultSection(dm, &section);}
3301:   DMGetDimension(dm, &dim);
3302:   PetscSectionGetNumFields(section, &Nf);
3303:   if (dim <= 1) return(0);
3304:   for (f = 0; f < Nf; ++f) {
3305:     /* An order k SEM disc has k-1 dofs on an edge */
3306:     DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3307:     PetscSectionGetFieldDof(section, eStart, f, &k);
3308:     PetscSectionGetFieldComponents(section, f, &Nc);
3309:     k = k/Nc + 1;
3310:     size += PetscPowInt(k+1, dim)*Nc;
3311:   }
3312:   PetscMalloc1(size, &perm);
3313:   for (f = 0; f < Nf; ++f) {
3314:     switch (dim) {
3315:     case 2:
3316:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3317:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3318:       PetscSectionGetFieldDof(section, eStart, f, &k);
3319:       PetscSectionGetFieldComponents(section, f, &Nc);
3320:       k = k/Nc + 1;
3321:       /* The SEM order is

3323:          v_lb, {e_b}, v_rb,
3324:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3325:          v_lt, reverse {e_t}, v_rt
3326:       */
3327:       {
3328:         const PetscInt of   = 0;
3329:         const PetscInt oeb  = of   + PetscSqr(k-1);
3330:         const PetscInt oer  = oeb  + (k-1);
3331:         const PetscInt oet  = oer  + (k-1);
3332:         const PetscInt oel  = oet  + (k-1);
3333:         const PetscInt ovlb = oel  + (k-1);
3334:         const PetscInt ovrb = ovlb + 1;
3335:         const PetscInt ovrt = ovrb + 1;
3336:         const PetscInt ovlt = ovrt + 1;
3337:         PetscInt       o;

3339:         /* bottom */
3340:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3341:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3342:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3343:         /* middle */
3344:         for (i = 0; i < k-1; ++i) {
3345:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3346:           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;
3347:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3348:         }
3349:         /* top */
3350:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3351:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3352:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3353:         foffset = offset;
3354:       }
3355:       break;
3356:     case 3:
3357:       /* The original hex closure is

3359:          {c,
3360:           f_b, f_t, f_f, f_b, f_r, f_l,
3361:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3362:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3363:       */
3364:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3365:       PetscSectionGetFieldDof(section, eStart, f, &k);
3366:       PetscSectionGetFieldComponents(section, f, &Nc);
3367:       k = k/Nc + 1;
3368:       /* The SEM order is
3369:          Bottom Slice
3370:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3371:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3372:          v_blb, {e_bb}, v_brb,

3374:          Middle Slice (j)
3375:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3376:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3377:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3379:          Top Slice
3380:          v_tlf, {e_tf}, v_trf,
3381:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3382:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3383:       */
3384:       {
3385:         const PetscInt oc    = 0;
3386:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3387:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3388:         const PetscInt off   = oft   + PetscSqr(k-1);
3389:         const PetscInt ofk   = off   + PetscSqr(k-1);
3390:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3391:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3392:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3393:         const PetscInt oebb  = oebl  + (k-1);
3394:         const PetscInt oebr  = oebb  + (k-1);
3395:         const PetscInt oebf  = oebr  + (k-1);
3396:         const PetscInt oetf  = oebf  + (k-1);
3397:         const PetscInt oetr  = oetf  + (k-1);
3398:         const PetscInt oetb  = oetr  + (k-1);
3399:         const PetscInt oetl  = oetb  + (k-1);
3400:         const PetscInt oerf  = oetl  + (k-1);
3401:         const PetscInt oelf  = oerf  + (k-1);
3402:         const PetscInt oelb  = oelf  + (k-1);
3403:         const PetscInt oerb  = oelb  + (k-1);
3404:         const PetscInt ovblf = oerb  + (k-1);
3405:         const PetscInt ovblb = ovblf + 1;
3406:         const PetscInt ovbrb = ovblb + 1;
3407:         const PetscInt ovbrf = ovbrb + 1;
3408:         const PetscInt ovtlf = ovbrf + 1;
3409:         const PetscInt ovtrf = ovtlf + 1;
3410:         const PetscInt ovtrb = ovtrf + 1;
3411:         const PetscInt ovtlb = ovtrb + 1;
3412:         PetscInt       o, n;

3414:         /* Bottom Slice */
3415:         /*   bottom */
3416:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3417:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3418:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3419:         /*   middle */
3420:         for (i = 0; i < k-1; ++i) {
3421:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3422:           for (n = 0; n < k-1; ++n) {o = ofb+n*(k-1)+(k-2)-i; for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;}
3423:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3424:         }
3425:         /*   top */
3426:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3427:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3428:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3430:         /* Middle Slice */
3431:         for (j = 0; j < k-1; ++j) {
3432:           /*   bottom */
3433:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3434:           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;
3435:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3436:           /*   middle */
3437:           for (i = 0; i < k-1; ++i) {
3438:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3439:             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;
3440:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3441:           }
3442:           /*   top */
3443:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3444:           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;
3445:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3446:         }

3448:         /* Top Slice */
3449:         /*   bottom */
3450:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3451:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3452:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3453:         /*   middle */
3454:         for (i = 0; i < k-1; ++i) {
3455:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3456:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3457:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3458:         }
3459:         /*   top */
3460:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3461:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3462:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3464:         foffset = offset;
3465:       }
3466:       break;
3467:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3468:     }
3469:   }
3470:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3471:   /* Check permutation */
3472:   {
3473:     PetscInt *check;

3475:     PetscMalloc1(size, &check);
3476:     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]);}
3477:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3478:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3479:     PetscFree(check);
3480:   }
3481:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3482:   return(0);
3483: }

3487: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3488: {
3489:   PetscScalar    *array, *vArray;
3490:   const PetscInt *cone, *coneO;
3491:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3492:   PetscErrorCode  ierr;

3495:   PetscSectionGetChart(section, &pStart, &pEnd);
3496:   DMPlexGetConeSize(dm, point, &numPoints);
3497:   DMPlexGetCone(dm, point, &cone);
3498:   DMPlexGetConeOrientation(dm, point, &coneO);
3499:   if (!values || !*values) {
3500:     if ((point >= pStart) && (point < pEnd)) {
3501:       PetscInt dof;

3503:       PetscSectionGetDof(section, point, &dof);
3504:       size += dof;
3505:     }
3506:     for (p = 0; p < numPoints; ++p) {
3507:       const PetscInt cp = cone[p];
3508:       PetscInt       dof;

3510:       if ((cp < pStart) || (cp >= pEnd)) continue;
3511:       PetscSectionGetDof(section, cp, &dof);
3512:       size += dof;
3513:     }
3514:     if (!values) {
3515:       if (csize) *csize = size;
3516:       return(0);
3517:     }
3518:     DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
3519:   } else {
3520:     array = *values;
3521:   }
3522:   size = 0;
3523:   VecGetArray(v, &vArray);
3524:   if ((point >= pStart) && (point < pEnd)) {
3525:     PetscInt     dof, off, d;
3526:     PetscScalar *varr;

3528:     PetscSectionGetDof(section, point, &dof);
3529:     PetscSectionGetOffset(section, point, &off);
3530:     varr = &vArray[off];
3531:     for (d = 0; d < dof; ++d, ++offset) {
3532:       array[offset] = varr[d];
3533:     }
3534:     size += dof;
3535:   }
3536:   for (p = 0; p < numPoints; ++p) {
3537:     const PetscInt cp = cone[p];
3538:     PetscInt       o  = coneO[p];
3539:     PetscInt       dof, off, d;
3540:     PetscScalar   *varr;

3542:     if ((cp < pStart) || (cp >= pEnd)) continue;
3543:     PetscSectionGetDof(section, cp, &dof);
3544:     PetscSectionGetOffset(section, cp, &off);
3545:     varr = &vArray[off];
3546:     if (o >= 0) {
3547:       for (d = 0; d < dof; ++d, ++offset) {
3548:         array[offset] = varr[d];
3549:       }
3550:     } else {
3551:       for (d = dof-1; d >= 0; --d, ++offset) {
3552:         array[offset] = varr[d];
3553:       }
3554:     }
3555:     size += dof;
3556:   }
3557:   VecRestoreArray(v, &vArray);
3558:   if (!*values) {
3559:     if (csize) *csize = size;
3560:     *values = array;
3561:   } else {
3562:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
3563:     *csize = size;
3564:   }
3565:   return(0);
3566: }

3570: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt perm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3571: {
3572:   PetscInt       offset = 0, p;

3576:   *size = 0;
3577:   for (p = 0; p < numPoints*2; p += 2) {
3578:     const PetscInt point = points[p];
3579:     const PetscInt o     = points[p+1];
3580:     PetscInt       dof, off, d;
3581:     const PetscScalar *varr;

3583:     PetscSectionGetDof(section, point, &dof);
3584:     PetscSectionGetOffset(section, point, &off);
3585:     varr = &vArray[off];
3586:     if (o >= 0) {
3587:       for (d = 0; d < dof; ++d, ++offset)    array[perm ? perm[offset] : offset] = varr[d];
3588:     } else {
3589:       for (d = dof-1; d >= 0; --d, ++offset) array[perm ? perm[offset] : offset] = varr[d];
3590:     }
3591:   }
3592:   *size = offset;
3593:   return(0);
3594: }

3598: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt perm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3599: {
3600:   PetscInt       offset = 0, f;

3604:   *size = 0;
3605:   for (f = 0; f < numFields; ++f) {
3606:     PetscInt fcomp, p;

3608:     PetscSectionGetFieldComponents(section, f, &fcomp);
3609:     for (p = 0; p < numPoints*2; p += 2) {
3610:       const PetscInt point = points[p];
3611:       const PetscInt o     = points[p+1];
3612:       PetscInt       fdof, foff, d, c;
3613:       const PetscScalar *varr;

3615:       PetscSectionGetFieldDof(section, point, f, &fdof);
3616:       PetscSectionGetFieldOffset(section, point, f, &foff);
3617:       varr = &vArray[foff];
3618:       if (o >= 0) {
3619:         for (d = 0; d < fdof; ++d, ++offset) array[perm ? perm[offset] : offset] = varr[d];
3620:       } else {
3621:         for (d = fdof/fcomp-1; d >= 0; --d) {
3622:           for (c = 0; c < fcomp; ++c, ++offset) {
3623:             array[perm ? perm[offset] : offset] = varr[d*fcomp+c];
3624:           }
3625:         }
3626:       }
3627:     }
3628:   }
3629:   *size = offset;
3630:   return(0);
3631: }

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

3638:   Not collective

3640:   Input Parameters:
3641: + dm - The DM
3642: . section - The section describing the layout in v, or NULL to use the default section
3643: . v - The local vector
3644: - point - The sieve point in the DM

3646:   Output Parameters:
3647: + csize - The number of values in the closure, or NULL
3648: - values - The array of values, which is a borrowed array and should not be freed

3650:   Fortran Notes:
3651:   Since it returns an array, this routine is only available in Fortran 90, and you must
3652:   include petsc.h90 in your code.

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

3656:   Level: intermediate

3658: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3659: @*/
3660: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3661: {
3662:   PetscSection    clSection;
3663:   IS              clPoints;
3664:   PetscScalar    *array, *vArray;
3665:   PetscInt       *points = NULL;
3666:   const PetscInt *clp, *perm;
3667:   PetscInt        depth, numFields, numPoints, size;
3668:   PetscErrorCode  ierr;

3672:   if (!section) {DMGetDefaultSection(dm, &section);}
3675:   DMPlexGetDepth(dm, &depth);
3676:   PetscSectionGetNumFields(section, &numFields);
3677:   if (depth == 1 && numFields < 2) {
3678:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
3679:     return(0);
3680:   }
3681:   /* Get points */
3682:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
3683:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
3684:   if (!clPoints) {
3685:     PetscInt pStart, pEnd, p, q;

3687:     PetscSectionGetChart(section, &pStart, &pEnd);
3688:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
3689:     /* Compress out points not in the section */
3690:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
3691:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
3692:         points[q*2]   = points[p];
3693:         points[q*2+1] = points[p+1];
3694:         ++q;
3695:       }
3696:     }
3697:     numPoints = q;
3698:   } else {
3699:     PetscInt dof, off;

3701:     PetscSectionGetDof(clSection, point, &dof);
3702:     PetscSectionGetOffset(clSection, point, &off);
3703:     ISGetIndices(clPoints, &clp);
3704:     numPoints = dof/2;
3705:     points    = (PetscInt *) &clp[off];
3706:   }
3707:   /* Get array */
3708:   if (!values || !*values) {
3709:     PetscInt asize = 0, dof, p;

3711:     for (p = 0; p < numPoints*2; p += 2) {
3712:       PetscSectionGetDof(section, points[p], &dof);
3713:       asize += dof;
3714:     }
3715:     if (!values) {
3716:       if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
3717:       else           {ISRestoreIndices(clPoints, &clp);}
3718:       if (csize) *csize = asize;
3719:       return(0);
3720:     }
3721:     DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
3722:   } else {
3723:     array = *values;
3724:   }
3725:   VecGetArray(v, &vArray);
3726:   /* Get values */
3727:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(section, numPoints, points, numFields, perm, vArray, &size, array);}
3728:   else               {DMPlexVecGetClosure_Static(section, numPoints, points, perm, vArray, &size, array);}
3729:   /* Cleanup points */
3730:   if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
3731:   else           {ISRestoreIndices(clPoints, &clp);}
3732:   /* Cleanup array */
3733:   VecRestoreArray(v, &vArray);
3734:   if (!*values) {
3735:     if (csize) *csize = size;
3736:     *values = array;
3737:   } else {
3738:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3739:     *csize = size;
3740:   }
3741:   return(0);
3742: }

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

3749:   Not collective

3751:   Input Parameters:
3752: + dm - The DM
3753: . section - The section describing the layout in v, or NULL to use the default section
3754: . v - The local vector
3755: . point - The sieve point in the DM
3756: . csize - The number of values in the closure, or NULL
3757: - values - The array of values, which is a borrowed array and should not be freed

3759:   Fortran Notes:
3760:   Since it returns an array, this routine is only available in Fortran 90, and you must
3761:   include petsc.h90 in your code.

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

3765:   Level: intermediate

3767: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3768: @*/
3769: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3770: {
3771:   PetscInt       size = 0;

3775:   /* Should work without recalculating size */
3776:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
3777:   return(0);
3778: }

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

3785: PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscInt perm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
3786: {
3787:   PetscInt        cdof;   /* The number of constraints on this point */
3788:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3789:   PetscScalar    *a;
3790:   PetscInt        off, cind = 0, k;
3791:   PetscErrorCode  ierr;

3794:   PetscSectionGetConstraintDof(section, point, &cdof);
3795:   PetscSectionGetOffset(section, point, &off);
3796:   a    = &array[off];
3797:   if (!cdof || setBC) {
3798:     if (orientation >= 0) {
3799:       for (k = 0; k < dof; ++k) {
3800:         fuse(&a[k], values[perm ? perm[offset+k] : offset+k]);
3801:       }
3802:     } else {
3803:       for (k = 0; k < dof; ++k) {
3804:         fuse(&a[k], values[perm ? perm[offset+dof-k-1] : offset+dof-k-1]);
3805:       }
3806:     }
3807:   } else {
3808:     PetscSectionGetConstraintIndices(section, point, &cdofs);
3809:     if (orientation >= 0) {
3810:       for (k = 0; k < dof; ++k) {
3811:         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3812:         fuse(&a[k], values[perm ? perm[offset+k] : offset+k]);
3813:       }
3814:     } else {
3815:       for (k = 0; k < dof; ++k) {
3816:         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3817:         fuse(&a[k], values[perm ? perm[offset+dof-k-1] : offset+dof-k-1]);
3818:       }
3819:     }
3820:   }
3821:   return(0);
3822: }

3826: PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscInt perm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
3827: {
3828:   PetscInt        cdof;   /* The number of constraints on this point */
3829:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3830:   PetscScalar    *a;
3831:   PetscInt        off, cind = 0, k;
3832:   PetscErrorCode  ierr;

3835:   PetscSectionGetConstraintDof(section, point, &cdof);
3836:   PetscSectionGetOffset(section, point, &off);
3837:   a    = &array[off];
3838:   if (cdof) {
3839:     PetscSectionGetConstraintIndices(section, point, &cdofs);
3840:     if (orientation >= 0) {
3841:       for (k = 0; k < dof; ++k) {
3842:         if ((cind < cdof) && (k == cdofs[cind])) {
3843:           fuse(&a[k], values[perm ? perm[offset+k] : offset+k]);
3844:           ++cind;
3845:         }
3846:       }
3847:     } else {
3848:       for (k = 0; k < dof; ++k) {
3849:         if ((cind < cdof) && (k == cdofs[cind])) {
3850:           fuse(&a[k], values[perm ? perm[offset+dof-k-1] : offset+dof-k-1]);
3851:           ++cind;
3852:         }
3853:       }
3854:     }
3855:   }
3856:   return(0);
3857: }

3861: PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
3862: {
3863:   PetscScalar    *a;
3864:   PetscInt        fdof, foff, fcdof, foffset = *offset;
3865:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
3866:   PetscInt        cind = 0, k, c;
3867:   PetscErrorCode  ierr;

3870:   PetscSectionGetFieldDof(section, point, f, &fdof);
3871:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
3872:   PetscSectionGetFieldOffset(section, point, f, &foff);
3873:   a    = &array[foff];
3874:   if (!fcdof || setBC) {
3875:     if (o >= 0) {
3876:       for (k = 0; k < fdof; ++k) fuse(&a[k], values[perm ? perm[foffset+k] : foffset+k]);
3877:     } else {
3878:       for (k = fdof/fcomp-1; k >= 0; --k) {
3879:         for (c = 0; c < fcomp; ++c) {
3880:           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[perm ? perm[foffset+k*fcomp+c] : foffset+k*fcomp+c]);
3881:         }
3882:       }
3883:     }
3884:   } else {
3885:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
3886:     if (o >= 0) {
3887:       for (k = 0; k < fdof; ++k) {
3888:         if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
3889:         fuse(&a[k], values[perm ? perm[foffset+k] : foffset+k]);
3890:       }
3891:     } else {
3892:       for (k = fdof/fcomp-1; k >= 0; --k) {
3893:         for (c = 0; c < fcomp; ++c) {
3894:           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
3895:           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[perm ? perm[foffset+k*fcomp+c] : foffset+k*fcomp+c]);
3896:         }
3897:       }
3898:     }
3899:   }
3900:   *offset += fdof;
3901:   return(0);
3902: }

3906: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt perm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
3907: {
3908:   PetscScalar    *a;
3909:   PetscInt        fdof, foff, fcdof, foffset = *offset;
3910:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
3911:   PetscInt        cind = 0, k, c;
3912:   PetscErrorCode  ierr;

3915:   PetscSectionGetFieldDof(section, point, f, &fdof);
3916:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
3917:   PetscSectionGetFieldOffset(section, point, f, &foff);
3918:   a    = &array[foff];
3919:   if (fcdof) {
3920:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
3921:     if (o >= 0) {
3922:       for (k = 0; k < fdof; ++k) {
3923:         if ((cind < fcdof) && (k == fcdofs[cind])) {
3924:           fuse(&a[k], values[perm ? perm[foffset+k] : foffset+k]);
3925:           ++cind;
3926:         }
3927:       }
3928:     } else {
3929:       for (k = fdof/fcomp-1; k >= 0; --k) {
3930:         for (c = 0; c < fcomp; ++c) {
3931:           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
3932:             fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[perm ? perm[foffset+k*fcomp+c] : foffset+k*fcomp+c]);
3933:             ++cind;
3934:           }
3935:         }
3936:       }
3937:     }
3938:   }
3939:   *offset += fdof;
3940:   return(0);
3941: }

3945: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
3946: {
3947:   PetscScalar    *array;
3948:   const PetscInt *cone, *coneO;
3949:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
3950:   PetscErrorCode  ierr;

3953:   PetscSectionGetChart(section, &pStart, &pEnd);
3954:   DMPlexGetConeSize(dm, point, &numPoints);
3955:   DMPlexGetCone(dm, point, &cone);
3956:   DMPlexGetConeOrientation(dm, point, &coneO);
3957:   VecGetArray(v, &array);
3958:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
3959:     const PetscInt cp = !p ? point : cone[p-1];
3960:     const PetscInt o  = !p ? 0     : coneO[p-1];

3962:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
3963:     PetscSectionGetDof(section, cp, &dof);
3964:     /* ADD_VALUES */
3965:     {
3966:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3967:       PetscScalar    *a;
3968:       PetscInt        cdof, coff, cind = 0, k;

3970:       PetscSectionGetConstraintDof(section, cp, &cdof);
3971:       PetscSectionGetOffset(section, cp, &coff);
3972:       a    = &array[coff];
3973:       if (!cdof) {
3974:         if (o >= 0) {
3975:           for (k = 0; k < dof; ++k) {
3976:             a[k] += values[off+k];
3977:           }
3978:         } else {
3979:           for (k = 0; k < dof; ++k) {
3980:             a[k] += values[off+dof-k-1];
3981:           }
3982:         }
3983:       } else {
3984:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
3985:         if (o >= 0) {
3986:           for (k = 0; k < dof; ++k) {
3987:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3988:             a[k] += values[off+k];
3989:           }
3990:         } else {
3991:           for (k = 0; k < dof; ++k) {
3992:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3993:             a[k] += values[off+dof-k-1];
3994:           }
3995:         }
3996:       }
3997:     }
3998:   }
3999:   VecRestoreArray(v, &array);
4000:   return(0);
4001: }

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

4008:   Not collective

4010:   Input Parameters:
4011: + dm - The DM
4012: . section - The section describing the layout in v, or NULL to use the default section
4013: . v - The local vector
4014: . point - The sieve point in the DM
4015: . values - The array of values
4016: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

4021:   Level: intermediate

4023: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4024: @*/
4025: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4026: {
4027:   PetscSection    clSection;
4028:   IS              clPoints;
4029:   PetscScalar    *array;
4030:   PetscInt       *points = NULL;
4031:   const PetscInt *clp, *perm;
4032:   PetscInt        depth, numFields, numPoints, p;
4033:   PetscErrorCode  ierr;

4037:   if (!section) {DMGetDefaultSection(dm, &section);}
4040:   DMPlexGetDepth(dm, &depth);
4041:   PetscSectionGetNumFields(section, &numFields);
4042:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4043:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4044:     return(0);
4045:   }
4046:   /* Get points */
4047:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4048:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
4049:   if (!clPoints) {
4050:     PetscInt pStart, pEnd, q;

4052:     PetscSectionGetChart(section, &pStart, &pEnd);
4053:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
4054:     /* Compress out points not in the section */
4055:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4056:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4057:         points[q*2]   = points[p];
4058:         points[q*2+1] = points[p+1];
4059:         ++q;
4060:       }
4061:     }
4062:     numPoints = q;
4063:   } else {
4064:     PetscInt dof, off;

4066:     PetscSectionGetDof(clSection, point, &dof);
4067:     PetscSectionGetOffset(clSection, point, &off);
4068:     ISGetIndices(clPoints, &clp);
4069:     numPoints = dof/2;
4070:     points    = (PetscInt *) &clp[off];
4071:   }
4072:   /* Get array */
4073:   VecGetArray(v, &array);
4074:   /* Get values */
4075:   if (numFields > 0) {
4076:     PetscInt offset = 0, fcomp, f;
4077:     for (f = 0; f < numFields; ++f) {
4078:       PetscSectionGetFieldComponents(section, f, &fcomp);
4079:       switch (mode) {
4080:       case INSERT_VALUES:
4081:         for (p = 0; p < numPoints*2; p += 2) {
4082:           const PetscInt point = points[p];
4083:           const PetscInt o     = points[p+1];
4084:           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, perm, values, &offset, array);
4085:         } break;
4086:       case INSERT_ALL_VALUES:
4087:         for (p = 0; p < numPoints*2; p += 2) {
4088:           const PetscInt point = points[p];
4089:           const PetscInt o     = points[p+1];
4090:           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, perm, values, &offset, array);
4091:         } break;
4092:       case INSERT_BC_VALUES:
4093:         for (p = 0; p < numPoints*2; p += 2) {
4094:           const PetscInt point = points[p];
4095:           const PetscInt o     = points[p+1];
4096:           updatePointFieldsBC_private(section, point, o, f, fcomp, insert, perm, values, &offset, array);
4097:         } break;
4098:       case ADD_VALUES:
4099:         for (p = 0; p < numPoints*2; p += 2) {
4100:           const PetscInt point = points[p];
4101:           const PetscInt o     = points[p+1];
4102:           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, perm, values, &offset, array);
4103:         } break;
4104:       case ADD_ALL_VALUES:
4105:         for (p = 0; p < numPoints*2; p += 2) {
4106:           const PetscInt point = points[p];
4107:           const PetscInt o     = points[p+1];
4108:           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, perm, values, &offset, array);
4109:         } break;
4110:       case ADD_BC_VALUES:
4111:         for (p = 0; p < numPoints*2; p += 2) {
4112:           const PetscInt point = points[p];
4113:           const PetscInt o     = points[p+1];
4114:           updatePointFieldsBC_private(section, point, o, f, fcomp, add, perm, values, &offset, array);
4115:         } break;
4116:       default:
4117:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4118:       }
4119:     }
4120:   } else {
4121:     PetscInt dof, off;

4123:     switch (mode) {
4124:     case INSERT_VALUES:
4125:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4126:         PetscInt o = points[p+1];
4127:         PetscSectionGetDof(section, points[p], &dof);
4128:         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, perm, values, off, array);
4129:       } break;
4130:     case INSERT_ALL_VALUES:
4131:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4132:         PetscInt o = points[p+1];
4133:         PetscSectionGetDof(section, points[p], &dof);
4134:         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, perm, values, off, array);
4135:       } break;
4136:     case INSERT_BC_VALUES:
4137:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4138:         PetscInt o = points[p+1];
4139:         PetscSectionGetDof(section, points[p], &dof);
4140:         updatePointBC_private(section, points[p], dof, insert,  o, perm, values, off, array);
4141:       } break;
4142:     case ADD_VALUES:
4143:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4144:         PetscInt o = points[p+1];
4145:         PetscSectionGetDof(section, points[p], &dof);
4146:         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, perm, values, off, array);
4147:       } break;
4148:     case ADD_ALL_VALUES:
4149:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4150:         PetscInt o = points[p+1];
4151:         PetscSectionGetDof(section, points[p], &dof);
4152:         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, perm, values, off, array);
4153:       } break;
4154:     case ADD_BC_VALUES:
4155:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4156:         PetscInt o = points[p+1];
4157:         PetscSectionGetDof(section, points[p], &dof);
4158:         updatePointBC_private(section, points[p], dof, add,  o, perm, values, off, array);
4159:       } break;
4160:     default:
4161:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4162:     }
4163:   }
4164:   /* Cleanup points */
4165:   if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
4166:   else           {ISRestoreIndices(clPoints, &clp);}
4167:   /* Cleanup array */
4168:   VecRestoreArray(v, &array);
4169:   return(0);
4170: }

4174: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
4175: {
4176:   PetscSection    clSection;
4177:   IS              clPoints;
4178:   PetscScalar    *array;
4179:   PetscInt       *points = NULL;
4180:   const PetscInt *clp, *perm;
4181:   PetscInt        numFields, numPoints, p;
4182:   PetscInt        offset = 0, fcomp, f;
4183:   PetscErrorCode  ierr;

4187:   if (!section) {DMGetDefaultSection(dm, &section);}
4190:   PetscSectionGetNumFields(section, &numFields);
4191:   /* Get points */
4192:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4193:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
4194:   if (!clPoints) {
4195:     PetscInt pStart, pEnd, q;

4197:     PetscSectionGetChart(section, &pStart, &pEnd);
4198:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
4199:     /* Compress out points not in the section */
4200:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4201:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4202:         points[q*2]   = points[p];
4203:         points[q*2+1] = points[p+1];
4204:         ++q;
4205:       }
4206:     }
4207:     numPoints = q;
4208:   } else {
4209:     PetscInt dof, off;

4211:     PetscSectionGetDof(clSection, point, &dof);
4212:     PetscSectionGetOffset(clSection, point, &off);
4213:     ISGetIndices(clPoints, &clp);
4214:     numPoints = dof/2;
4215:     points    = (PetscInt *) &clp[off];
4216:   }
4217:   /* Get array */
4218:   VecGetArray(v, &array);
4219:   /* Get values */
4220:   for (f = 0; f < numFields; ++f) {
4221:     PetscSectionGetFieldComponents(section, f, &fcomp);
4222:     if (!fieldActive[f]) {
4223:       for (p = 0; p < numPoints*2; p += 2) {
4224:         PetscInt fdof;
4225:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4226:         offset += fdof;
4227:       }
4228:       continue;
4229:     }
4230:     switch (mode) {
4231:     case INSERT_VALUES:
4232:       for (p = 0; p < numPoints*2; p += 2) {
4233:         const PetscInt point = points[p];
4234:         const PetscInt o     = points[p+1];
4235:         updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, perm, values, &offset, array);
4236:       } break;
4237:     case INSERT_ALL_VALUES:
4238:       for (p = 0; p < numPoints*2; p += 2) {
4239:         const PetscInt point = points[p];
4240:         const PetscInt o     = points[p+1];
4241:         updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, perm, values, &offset, array);
4242:         } break;
4243:     case INSERT_BC_VALUES:
4244:       for (p = 0; p < numPoints*2; p += 2) {
4245:         const PetscInt point = points[p];
4246:         const PetscInt o     = points[p+1];
4247:         updatePointFieldsBC_private(section, point, o, f, fcomp, insert, perm, values, &offset, array);
4248:       } break;
4249:     case ADD_VALUES:
4250:       for (p = 0; p < numPoints*2; p += 2) {
4251:         const PetscInt point = points[p];
4252:         const PetscInt o     = points[p+1];
4253:         updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, perm, values, &offset, array);
4254:       } break;
4255:     case ADD_ALL_VALUES:
4256:       for (p = 0; p < numPoints*2; p += 2) {
4257:         const PetscInt point = points[p];
4258:         const PetscInt o     = points[p+1];
4259:         updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, perm, values, &offset, array);
4260:       } break;
4261:     default:
4262:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4263:     }
4264:   }
4265:   /* Cleanup points */
4266:   if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
4267:   else           {ISRestoreIndices(clPoints, &clp);}
4268:   /* Cleanup array */
4269:   VecRestoreArray(v, &array);
4270:   return(0);
4271: }

4275: PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4276: {
4277:   PetscMPIInt    rank;
4278:   PetscInt       i, j;

4282:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4283:   PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);
4284:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4285:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4286:   numCIndices = numCIndices ? numCIndices : numRIndices;
4287:   for (i = 0; i < numRIndices; i++) {
4288:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4289:     for (j = 0; j < numCIndices; j++) {
4290: #if defined(PETSC_USE_COMPLEX)
4291:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4292: #else
4293:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4294: #endif
4295:     }
4296:     PetscViewerASCIIPrintf(viewer, "\n");
4297:   }
4298:   return(0);
4299: }

4303: /* . off - The global offset of this point */
4304: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
4305: {
4306:   PetscInt        dof;    /* The number of unknowns on this point */
4307:   PetscInt        cdof;   /* The number of constraints on this point */
4308:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4309:   PetscInt        cind = 0, k;
4310:   PetscErrorCode  ierr;

4313:   PetscSectionGetDof(section, point, &dof);
4314:   PetscSectionGetConstraintDof(section, point, &cdof);
4315:   if (!cdof || setBC) {
4316:     if (orientation >= 0) {
4317:       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
4318:     } else {
4319:       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
4320:     }
4321:   } else {
4322:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4323:     if (orientation >= 0) {
4324:       for (k = 0; k < dof; ++k) {
4325:         if ((cind < cdof) && (k == cdofs[cind])) {
4326:           /* Insert check for returning constrained indices */
4327:           indices[*loff+k] = -(off+k+1);
4328:           ++cind;
4329:         } else {
4330:           indices[*loff+k] = off+k-cind;
4331:         }
4332:       }
4333:     } else {
4334:       for (k = 0; k < dof; ++k) {
4335:         if ((cind < cdof) && (k == cdofs[cind])) {
4336:           /* Insert check for returning constrained indices */
4337:           indices[*loff+dof-k-1] = -(off+k+1);
4338:           ++cind;
4339:         } else {
4340:           indices[*loff+dof-k-1] = off+k-cind;
4341:         }
4342:       }
4343:     }
4344:   }
4345:   *loff += dof;
4346:   return(0);
4347: }

4351: /* . off - The global offset of this point */
4352: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
4353: {
4354:   PetscInt       numFields, foff, f;

4358:   PetscSectionGetNumFields(section, &numFields);
4359:   for (f = 0, foff = 0; f < numFields; ++f) {
4360:     PetscInt        fdof, fcomp, cfdof;
4361:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4362:     PetscInt        cind = 0, k, c;

4364:     PetscSectionGetFieldComponents(section, f, &fcomp);
4365:     PetscSectionGetFieldDof(section, point, f, &fdof);
4366:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4367:     if (!cfdof || setBC) {
4368:       if (orientation >= 0) {
4369:         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
4370:       } else {
4371:         for (k = fdof/fcomp-1; k >= 0; --k) {
4372:           for (c = 0; c < fcomp; ++c) {
4373:             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
4374:           }
4375:         }
4376:       }
4377:     } else {
4378:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4379:       if (orientation >= 0) {
4380:         for (k = 0; k < fdof; ++k) {
4381:           if ((cind < cfdof) && (k == fcdofs[cind])) {
4382:             indices[foffs[f]+k] = -(off+foff+k+1);
4383:             ++cind;
4384:           } else {
4385:             indices[foffs[f]+k] = off+foff+k-cind;
4386:           }
4387:         }
4388:       } else {
4389:         for (k = fdof/fcomp-1; k >= 0; --k) {
4390:           for (c = 0; c < fcomp; ++c) {
4391:             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
4392:               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
4393:               ++cind;
4394:             } else {
4395:               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
4396:             }
4397:           }
4398:         }
4399:       }
4400:     }
4401:     foff     += (setBC ? fdof : (fdof - cfdof));
4402:     foffs[f] += fdof;
4403:   }
4404:   return(0);
4405: }

4409: PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft)
4410: {
4411:   Mat             cMat;
4412:   PetscSection    aSec, cSec;
4413:   IS              aIS;
4414:   PetscInt        aStart = -1, aEnd = -1;
4415:   const PetscInt  *anchors;
4416:   PetscInt        numFields, f, p, q, newP = 0;
4417:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4418:   PetscInt        *newPoints, *indices, *newIndices;
4419:   PetscInt        maxAnchor, maxDof;
4420:   PetscInt        newOffsets[32];
4421:   PetscInt        *pointMatOffsets[32];
4422:   PetscInt        *newPointOffsets[32];
4423:   PetscScalar     *pointMat[32];
4424:   PetscScalar     *newValues=NULL,*tmpValues;
4425:   PetscBool       anyConstrained = PETSC_FALSE;
4426:   PetscErrorCode  ierr;

4431:   PetscSectionGetNumFields(section, &numFields);

4433:   DMPlexGetAnchors(dm,&aSec,&aIS);
4434:   /* if there are point-to-point constraints */
4435:   if (aSec) {
4436:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4437:     ISGetIndices(aIS,&anchors);
4438:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4439:     /* figure out how many points are going to be in the new element matrix
4440:      * (we allow double counting, because it's all just going to be summed
4441:      * into the global matrix anyway) */
4442:     for (p = 0; p < 2*numPoints; p+=2) {
4443:       PetscInt b    = points[p];
4444:       PetscInt bDof = 0, bSecDof;

4446:       PetscSectionGetDof(section,b,&bSecDof);
4447:       if (!bSecDof) {
4448:         continue;
4449:       }
4450:       if (b >= aStart && b < aEnd) {
4451:         PetscSectionGetDof(aSec,b,&bDof);
4452:       }
4453:       if (bDof) {
4454:         /* this point is constrained */
4455:         /* it is going to be replaced by its anchors */
4456:         PetscInt bOff, q;

4458:         anyConstrained = PETSC_TRUE;
4459:         newNumPoints  += bDof;
4460:         PetscSectionGetOffset(aSec,b,&bOff);
4461:         for (q = 0; q < bDof; q++) {
4462:           PetscInt a = anchors[bOff + q];
4463:           PetscInt aDof;

4465:           PetscSectionGetDof(section,a,&aDof);
4466:           newNumIndices += aDof;
4467:           for (f = 0; f < numFields; ++f) {
4468:             PetscInt fDof;

4470:             PetscSectionGetFieldDof(section, a, f, &fDof);
4471:             newOffsets[f+1] += fDof;
4472:           }
4473:         }
4474:       }
4475:       else {
4476:         /* this point is not constrained */
4477:         newNumPoints++;
4478:         newNumIndices += bSecDof;
4479:         for (f = 0; f < numFields; ++f) {
4480:           PetscInt fDof;

4482:           PetscSectionGetFieldDof(section, b, f, &fDof);
4483:           newOffsets[f+1] += fDof;
4484:         }
4485:       }
4486:     }
4487:   }
4488:   if (!anyConstrained) {
4489:     if (outNumPoints)  *outNumPoints  = 0;
4490:     if (outNumIndices) *outNumIndices = 0;
4491:     if (outPoints)     *outPoints     = NULL;
4492:     if (outValues)     *outValues     = NULL;
4493:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4494:     return(0);
4495:   }

4497:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4498:   if (outNumIndices) *outNumIndices = newNumIndices;

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

4502:   if (!outPoints && !outValues) {
4503:     if (offsets) {
4504:       for (f = 0; f <= numFields; f++) {
4505:         offsets[f] = newOffsets[f];
4506:       }
4507:     }
4508:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4509:     return(0);
4510:   }

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

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

4516:   /* workspaces */
4517:   if (numFields) {
4518:     for (f = 0; f < numFields; f++) {
4519:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
4520:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
4521:     }
4522:   }
4523:   else {
4524:     DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
4525:     DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);
4526:   }

4528:   /* get workspaces for the point-to-point matrices */
4529:   if (numFields) {
4530:     PetscInt totalOffset, totalMatOffset;

4532:     for (p = 0; p < numPoints; p++) {
4533:       PetscInt b    = points[2*p];
4534:       PetscInt bDof = 0, bSecDof;

4536:       PetscSectionGetDof(section,b,&bSecDof);
4537:       if (!bSecDof) {
4538:         for (f = 0; f < numFields; f++) {
4539:           newPointOffsets[f][p + 1] = 0;
4540:           pointMatOffsets[f][p + 1] = 0;
4541:         }
4542:         continue;
4543:       }
4544:       if (b >= aStart && b < aEnd) {
4545:         PetscSectionGetDof(aSec, b, &bDof);
4546:       }
4547:       if (bDof) {
4548:         for (f = 0; f < numFields; f++) {
4549:           PetscInt fDof, q, bOff, allFDof = 0;

4551:           PetscSectionGetFieldDof(section, b, f, &fDof);
4552:           PetscSectionGetOffset(aSec, b, &bOff);
4553:           for (q = 0; q < bDof; q++) {
4554:             PetscInt a = anchors[bOff + q];
4555:             PetscInt aFDof;

4557:             PetscSectionGetFieldDof(section, a, f, &aFDof);
4558:             allFDof += aFDof;
4559:           }
4560:           newPointOffsets[f][p+1] = allFDof;
4561:           pointMatOffsets[f][p+1] = fDof * allFDof;
4562:         }
4563:       }
4564:       else {
4565:         for (f = 0; f < numFields; f++) {
4566:           PetscInt fDof;

4568:           PetscSectionGetFieldDof(section, b, f, &fDof);
4569:           newPointOffsets[f][p+1] = fDof;
4570:           pointMatOffsets[f][p+1] = 0;
4571:         }
4572:       }
4573:     }
4574:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
4575:       newPointOffsets[f][0] = totalOffset;
4576:       pointMatOffsets[f][0] = totalMatOffset;
4577:       for (p = 0; p < numPoints; p++) {
4578:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4579:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4580:       }
4581:       totalOffset    = newPointOffsets[f][numPoints];
4582:       totalMatOffset = pointMatOffsets[f][numPoints];
4583:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
4584:     }
4585:   }
4586:   else {
4587:     for (p = 0; p < numPoints; p++) {
4588:       PetscInt b    = points[2*p];
4589:       PetscInt bDof = 0, bSecDof;

4591:       PetscSectionGetDof(section,b,&bSecDof);
4592:       if (!bSecDof) {
4593:         newPointOffsets[0][p + 1] = 0;
4594:         pointMatOffsets[0][p + 1] = 0;
4595:         continue;
4596:       }
4597:       if (b >= aStart && b < aEnd) {
4598:         PetscSectionGetDof(aSec, b, &bDof);
4599:       }
4600:       if (bDof) {
4601:         PetscInt bOff, q, allDof = 0;

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

4607:           PetscSectionGetDof(section, a, &aDof);
4608:           allDof += aDof;
4609:         }
4610:         newPointOffsets[0][p+1] = allDof;
4611:         pointMatOffsets[0][p+1] = bSecDof * allDof;
4612:       }
4613:       else {
4614:         newPointOffsets[0][p+1] = bSecDof;
4615:         pointMatOffsets[0][p+1] = 0;
4616:       }
4617:     }
4618:     newPointOffsets[0][0] = 0;
4619:     pointMatOffsets[0][0] = 0;
4620:     for (p = 0; p < numPoints; p++) {
4621:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4622:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4623:     }
4624:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
4625:   }

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

4630:   /* get the point-to-point matrices; construct newPoints */
4631:   PetscSectionGetMaxDof(aSec, &maxAnchor);
4632:   PetscSectionGetMaxDof(section, &maxDof);
4633:   DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);
4634:   DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
4635:   if (numFields) {
4636:     for (p = 0, newP = 0; p < numPoints; p++) {
4637:       PetscInt b    = points[2*p];
4638:       PetscInt o    = points[2*p+1];
4639:       PetscInt bDof = 0, bSecDof;

4641:       PetscSectionGetDof(section, b, &bSecDof);
4642:       if (!bSecDof) {
4643:         continue;
4644:       }
4645:       if (b >= aStart && b < aEnd) {
4646:         PetscSectionGetDof(aSec, b, &bDof);
4647:       }
4648:       if (bDof) {
4649:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

4651:         fStart[0] = 0;
4652:         fEnd[0]   = 0;
4653:         for (f = 0; f < numFields; f++) {
4654:           PetscInt fDof;

4656:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
4657:           fStart[f+1] = fStart[f] + fDof;
4658:           fEnd[f+1]   = fStart[f+1];
4659:         }
4660:         PetscSectionGetOffset(cSec, b, &bOff);
4661:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, o, indices);

4663:         fAnchorStart[0] = 0;
4664:         fAnchorEnd[0]   = 0;
4665:         for (f = 0; f < numFields; f++) {
4666:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

4668:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4669:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4670:         }
4671:         PetscSectionGetOffset(aSec, b, &bOff);
4672:         for (q = 0; q < bDof; q++) {
4673:           PetscInt a = anchors[bOff + q], aOff;

4675:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4676:           newPoints[2*(newP + q)]     = a;
4677:           newPoints[2*(newP + q) + 1] = 0;
4678:           PetscSectionGetOffset(section, a, &aOff);
4679:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, 0, newIndices);
4680:         }
4681:         newP += bDof;

4683:         if (outValues) {
4684:           /* get the point-to-point submatrix */
4685:           for (f = 0; f < numFields; f++) {
4686:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
4687:           }
4688:         }
4689:       }
4690:       else {
4691:         newPoints[2 * newP]     = b;
4692:         newPoints[2 * newP + 1] = o;
4693:         newP++;
4694:       }
4695:     }
4696:   } else {
4697:     for (p = 0; p < numPoints; p++) {
4698:       PetscInt b    = points[2*p];
4699:       PetscInt o    = points[2*p+1];
4700:       PetscInt bDof = 0, bSecDof;

4702:       PetscSectionGetDof(section, b, &bSecDof);
4703:       if (!bSecDof) {
4704:         continue;
4705:       }
4706:       if (b >= aStart && b < aEnd) {
4707:         PetscSectionGetDof(aSec, b, &bDof);
4708:       }
4709:       if (bDof) {
4710:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

4712:         PetscSectionGetOffset(cSec, b, &bOff);
4713:         DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, o, indices);

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

4719:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */

4721:           newPoints[2*(newP + q)]     = a;
4722:           newPoints[2*(newP + q) + 1] = 0;
4723:           PetscSectionGetOffset(section, a, &aOff);
4724:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, 0, newIndices);
4725:         }
4726:         newP += bDof;

4728:         /* get the point-to-point submatrix */
4729:         if (outValues) {
4730:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
4731:         }
4732:       }
4733:       else {
4734:         newPoints[2 * newP]     = b;
4735:         newPoints[2 * newP + 1] = o;
4736:         newP++;
4737:       }
4738:     }
4739:   }

4741:   if (outValues) {
4742:     DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
4743:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
4744:     /* multiply constraints on the right */
4745:     if (numFields) {
4746:       for (f = 0; f < numFields; f++) {
4747:         PetscInt oldOff = offsets[f];

4749:         for (p = 0; p < numPoints; p++) {
4750:           PetscInt cStart = newPointOffsets[f][p];
4751:           PetscInt b      = points[2 * p];
4752:           PetscInt c, r, k;
4753:           PetscInt dof;

4755:           PetscSectionGetFieldDof(section,b,f,&dof);
4756:           if (!dof) {
4757:             continue;
4758:           }
4759:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4760:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
4761:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

4763:             for (r = 0; r < numIndices; r++) {
4764:               for (c = 0; c < nCols; c++) {
4765:                 for (k = 0; k < dof; k++) {
4766:                   tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
4767:                 }
4768:               }
4769:             }
4770:           }
4771:           else {
4772:             /* copy this column as is */
4773:             for (r = 0; r < numIndices; r++) {
4774:               for (c = 0; c < dof; c++) {
4775:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4776:               }
4777:             }
4778:           }
4779:           oldOff += dof;
4780:         }
4781:       }
4782:     }
4783:     else {
4784:       PetscInt oldOff = 0;
4785:       for (p = 0; p < numPoints; p++) {
4786:         PetscInt cStart = newPointOffsets[0][p];
4787:         PetscInt b      = points[2 * p];
4788:         PetscInt c, r, k;
4789:         PetscInt dof;

4791:         PetscSectionGetDof(section,b,&dof);
4792:         if (!dof) {
4793:           continue;
4794:         }
4795:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
4796:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
4797:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

4799:           for (r = 0; r < numIndices; r++) {
4800:             for (c = 0; c < nCols; c++) {
4801:               for (k = 0; k < dof; k++) {
4802:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
4803:               }
4804:             }
4805:           }
4806:         }
4807:         else {
4808:           /* copy this column as is */
4809:           for (r = 0; r < numIndices; r++) {
4810:             for (c = 0; c < dof; c++) {
4811:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4812:             }
4813:           }
4814:         }
4815:         oldOff += dof;
4816:       }
4817:     }

4819:     if (multiplyLeft) {
4820:       DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
4821:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
4822:       /* multiply constraints transpose on the left */
4823:       if (numFields) {
4824:         for (f = 0; f < numFields; f++) {
4825:           PetscInt oldOff = offsets[f];

4827:           for (p = 0; p < numPoints; p++) {
4828:             PetscInt rStart = newPointOffsets[f][p];
4829:             PetscInt b      = points[2 * p];
4830:             PetscInt c, r, k;
4831:             PetscInt dof;

4833:             PetscSectionGetFieldDof(section,b,f,&dof);
4834:             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4835:               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
4836:               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];

4838:               for (r = 0; r < nRows; r++) {
4839:                 for (c = 0; c < newNumIndices; c++) {
4840:                   for (k = 0; k < dof; k++) {
4841:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
4842:                   }
4843:                 }
4844:               }
4845:             }
4846:             else {
4847:               /* copy this row as is */
4848:               for (r = 0; r < dof; r++) {
4849:                 for (c = 0; c < newNumIndices; c++) {
4850:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
4851:                 }
4852:               }
4853:             }
4854:             oldOff += dof;
4855:           }
4856:         }
4857:       }
4858:       else {
4859:         PetscInt oldOff = 0;

4861:         for (p = 0; p < numPoints; p++) {
4862:           PetscInt rStart = newPointOffsets[0][p];
4863:           PetscInt b      = points[2 * p];
4864:           PetscInt c, r, k;
4865:           PetscInt dof;

4867:           PetscSectionGetDof(section,b,&dof);
4868:           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
4869:             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
4870:             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];

4872:             for (r = 0; r < nRows; r++) {
4873:               for (c = 0; c < newNumIndices; c++) {
4874:                 for (k = 0; k < dof; k++) {
4875:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
4876:                 }
4877:               }
4878:             }
4879:           }
4880:           else {
4881:             /* copy this row as is */
4882:             for (r = 0; r < dof; r++) {
4883:               for (c = 0; c < newNumIndices; c++) {
4884:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
4885:               }
4886:             }
4887:           }
4888:           oldOff += dof;
4889:         }
4890:       }

4892:       DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
4893:     }
4894:     else {
4895:       newValues = tmpValues;
4896:     }
4897:   }

4899:   /* clean up */
4900:   DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);
4901:   DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);

4903:   if (numFields) {
4904:     for (f = 0; f < numFields; f++) {
4905:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
4906:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
4907:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
4908:     }
4909:   }
4910:   else {
4911:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
4912:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
4913:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);
4914:   }
4915:   ISRestoreIndices(aIS,&anchors);

4917:   /* output */
4918:   if (outPoints) {
4919:     *outPoints = newPoints;
4920:   }
4921:   else {
4922:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
4923:   }
4924:   if (outValues) {
4925:     *outValues = newValues;
4926:   }
4927:   for (f = 0; f <= numFields; f++) {
4928:     offsets[f] = newOffsets[f];
4929:   }
4930:   return(0);
4931: }

4935: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
4936: {
4937:   PetscSection    clSection;
4938:   IS              clPoints;
4939:   const PetscInt *clp;
4940:   PetscInt       *points = NULL, *pointsNew;
4941:   PetscInt        numPoints, numPointsNew;
4942:   PetscInt        offsets[32];
4943:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
4944:   PetscErrorCode  ierr;

4952:   PetscSectionGetNumFields(section, &Nf);
4953:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
4954:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
4955:   /* Get points in closure */
4956:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
4957:   if (!clPoints) {
4958:     PetscInt pStart, pEnd, q;

4960:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
4961:     /* Compress out points not in the section */
4962:     PetscSectionGetChart(section, &pStart, &pEnd);
4963:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4964:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4965:         points[q*2]   = points[p];
4966:         points[q*2+1] = points[p+1];
4967:         ++q;
4968:       }
4969:     }
4970:     numPoints = q;
4971:   } else {
4972:     PetscInt dof, off;

4974:     PetscSectionGetDof(clSection, point, &dof);
4975:     numPoints = dof/2;
4976:     PetscSectionGetOffset(clSection, point, &off);
4977:     ISGetIndices(clPoints, &clp);
4978:     points = (PetscInt *) &clp[off];
4979:   }
4980:   /* Get number of indices and indices per field */
4981:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
4982:     PetscInt dof, fdof;

4984:     PetscSectionGetDof(section, points[p], &dof);
4985:     for (f = 0; f < Nf; ++f) {
4986:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
4987:       offsets[f+1] += fdof;
4988:     }
4989:     Nind += dof;
4990:   }
4991:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
4992:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[Nf], Nind);
4993:   /* Correct for hanging node constraints */
4994:   {
4995:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
4996:     if (numPointsNew) {
4997:       if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
4998:       else           {ISRestoreIndices(clPoints, &clp);}
4999:       numPoints = numPointsNew;
5000:       Nind      = NindNew;
5001:       points    = pointsNew;
5002:     }
5003:   }
5004:   /* Calculate indices */
5005:   DMGetWorkArray(dm, Nind, PETSC_INT, indices);
5006:   if (Nf) {
5007:     if (outOffsets) {
5008:       PetscInt f;

5010:       for (f = 0; f <= Nf; f++) {
5011:         outOffsets[f] = offsets[f];
5012:       }
5013:     }
5014:     for (p = 0; p < numPoints*2; p += 2) {
5015:       PetscInt o = points[p+1];
5016:       PetscSectionGetOffset(globalSection, points[p], &globalOff);
5017:       DMPlexGetIndicesPointFields_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, *indices);
5018:     }
5019:   } else {
5020:     for (p = 0, off = 0; p < numPoints*2; p += 2) {
5021:       PetscInt o = points[p+1];
5022:       PetscSectionGetOffset(globalSection, points[p], &globalOff);
5023:       DMPlexGetIndicesPoint_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, *indices);
5024:     }
5025:   }
5026:   /* Cleanup points */
5027:   if (numPointsNew) {
5028:     DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);
5029:   } else {
5030:     if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
5031:     else           {ISRestoreIndices(clPoints, &clp);}
5032:   }
5033:   if (numIndices) *numIndices = Nind;
5034:   return(0);
5035: }

5039: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5040: {

5046:   DMRestoreWorkArray(dm, 0, PETSC_INT, indices);
5047:   return(0);
5048: }

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

5055:   Not collective

5057:   Input Parameters:
5058: + dm - The DM
5059: . section - The section describing the layout in v, or NULL to use the default section
5060: . globalSection - The section describing the layout in v, or NULL to use the default global section
5061: . A - The matrix
5062: . point - The sieve point in the DM
5063: . values - The array of values
5064: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5069:   Level: intermediate

5071: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5072: @*/
5073: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5074: {
5075:   DM_Plex        *mesh   = (DM_Plex*) dm->data;
5076:   PetscSection    clSection;
5077:   IS              clPoints;
5078:   PetscInt       *points = NULL, *newPoints;
5079:   const PetscInt *clp;
5080:   PetscInt       *indices;
5081:   PetscInt        offsets[32];
5082:   PetscInt        numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
5083:   PetscScalar    *newValues;
5084:   PetscErrorCode  ierr;

5088:   if (!section) {DMGetDefaultSection(dm, &section);}
5090:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5093:   PetscSectionGetNumFields(section, &numFields);
5094:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5095:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5096:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
5097:   if (!clPoints) {
5098:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5099:     /* Compress out points not in the section */
5100:     PetscSectionGetChart(section, &pStart, &pEnd);
5101:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
5102:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
5103:         points[q*2]   = points[p];
5104:         points[q*2+1] = points[p+1];
5105:         ++q;
5106:       }
5107:     }
5108:     numPoints = q;
5109:   } else {
5110:     PetscInt dof, off;

5112:     PetscSectionGetDof(clSection, point, &dof);
5113:     numPoints = dof/2;
5114:     PetscSectionGetOffset(clSection, point, &off);
5115:     ISGetIndices(clPoints, &clp);
5116:     points = (PetscInt *) &clp[off];
5117:   }
5118:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5119:     PetscInt fdof;

5121:     PetscSectionGetDof(section, points[p], &dof);
5122:     for (f = 0; f < numFields; ++f) {
5123:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5124:       offsets[f+1] += fdof;
5125:     }
5126:     numIndices += dof;
5127:   }
5128:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

5130:   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
5131:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5132:   if (newNumPoints) {
5133:     if (!clPoints) {
5134:       DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5135:     } else {
5136:       ISRestoreIndices(clPoints, &clp);
5137:     }
5138:     numPoints  = newNumPoints;
5139:     numIndices = newNumIndices;
5140:     points     = newPoints;
5141:     values     = newValues;
5142:   }
5143:   DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
5144:   if (numFields) {
5145:     for (p = 0; p < numPoints*2; p += 2) {
5146:       PetscInt o = points[p+1];
5147:       PetscSectionGetOffset(globalSection, points[p], &globalOff);
5148:       DMPlexGetIndicesPointFields_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
5149:     }
5150:   } else {
5151:     for (p = 0, off = 0; p < numPoints*2; p += 2) {
5152:       PetscInt o = points[p+1];
5153:       PetscSectionGetOffset(globalSection, points[p], &globalOff);
5154:       DMPlexGetIndicesPoint_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
5155:     }
5156:   }
5157:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5158:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5159:   if (mesh->printFEM > 1) {
5160:     PetscInt i;
5161:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5162:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %d", indices[i]);}
5163:     PetscPrintf(PETSC_COMM_SELF, "\n");
5164:   }
5165:   if (ierr) {
5166:     PetscMPIInt    rank;
5167:     PetscErrorCode ierr2;

5169:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5170:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5171:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5172:     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5173: 
5174:   }
5175:   if (newNumPoints) {
5176:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5177:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5178:   }
5179:   else {
5180:     if (!clPoints) {
5181:       DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5182:     } else {
5183:       ISRestoreIndices(clPoints, &clp);
5184:     }
5185:   }
5186:   DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
5187:   return(0);
5188: }

5192: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5193: {
5194:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5195:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5196:   PetscInt       *cpoints = NULL;
5197:   PetscInt       *findices, *cindices;
5198:   PetscInt        foffsets[32], coffsets[32];
5199:   CellRefiner     cellRefiner;
5200:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5201:   PetscErrorCode  ierr;

5206:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5208:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5210:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5212:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5215:   PetscSectionGetNumFields(fsection, &numFields);
5216:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5217:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5218:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5219:   /* Column indices */
5220:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5221:   maxFPoints = numCPoints;
5222:   /* Compress out points not in the section */
5223:   /*   TODO: Squeeze out points with 0 dof as well */
5224:   PetscSectionGetChart(csection, &pStart, &pEnd);
5225:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5226:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5227:       cpoints[q*2]   = cpoints[p];
5228:       cpoints[q*2+1] = cpoints[p+1];
5229:       ++q;
5230:     }
5231:   }
5232:   numCPoints = q;
5233:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5234:     PetscInt fdof;

5236:     PetscSectionGetDof(csection, cpoints[p], &dof);
5237:     if (!dof) continue;
5238:     for (f = 0; f < numFields; ++f) {
5239:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5240:       coffsets[f+1] += fdof;
5241:     }
5242:     numCIndices += dof;
5243:   }
5244:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5245:   /* Row indices */
5246:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5247:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5248:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5249:   for (r = 0, q = 0; r < numSubcells; ++r) {
5250:     /* TODO Map from coarse to fine cells */
5251:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5252:     /* Compress out points not in the section */
5253:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5254:     for (p = 0; p < numFPoints*2; p += 2) {
5255:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5256:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5257:         if (!dof) continue;
5258:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5259:         if (s < q) continue;
5260:         ftotpoints[q*2]   = fpoints[p];
5261:         ftotpoints[q*2+1] = fpoints[p+1];
5262:         ++q;
5263:       }
5264:     }
5265:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5266:   }
5267:   numFPoints = q;
5268:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5269:     PetscInt fdof;

5271:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5272:     if (!dof) continue;
5273:     for (f = 0; f < numFields; ++f) {
5274:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5275:       foffsets[f+1] += fdof;
5276:     }
5277:     numFIndices += dof;
5278:   }
5279:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5281:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
5282:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
5283:   DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5284:   DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5285:   if (numFields) {
5286:     for (p = 0; p < numFPoints*2; p += 2) {
5287:       PetscInt o = ftotpoints[p+1];
5288:       PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);
5289:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
5290:     }
5291:     for (p = 0; p < numCPoints*2; p += 2) {
5292:       PetscInt o = cpoints[p+1];
5293:       PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);
5294:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
5295:     }
5296:   } else {
5297:     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
5298:       PetscInt o = ftotpoints[p+1];
5299:       PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);
5300:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
5301:     }
5302:     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
5303:       PetscInt o = cpoints[p+1];
5304:       PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);
5305:       DMPlexGetIndicesPoint_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
5306:     }
5307:   }
5308:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5309:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5310:   if (ierr) {
5311:     PetscMPIInt    rank;
5312:     PetscErrorCode ierr2;

5314:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5315:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5316:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5317:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5318:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5319: 
5320:   }
5321:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5322:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5323:   DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5324:   DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5325:   return(0);
5326: }

5330: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5331: {
5332:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5333:   PetscInt      *cpoints = NULL;
5334:   PetscInt       foffsets[32], coffsets[32];
5335:   CellRefiner    cellRefiner;
5336:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

5342:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5344:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5346:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5348:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5350:   PetscSectionGetNumFields(fsection, &numFields);
5351:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5352:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5353:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5354:   /* Column indices */
5355:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5356:   maxFPoints = numCPoints;
5357:   /* Compress out points not in the section */
5358:   /*   TODO: Squeeze out points with 0 dof as well */
5359:   PetscSectionGetChart(csection, &pStart, &pEnd);
5360:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5361:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5362:       cpoints[q*2]   = cpoints[p];
5363:       cpoints[q*2+1] = cpoints[p+1];
5364:       ++q;
5365:     }
5366:   }
5367:   numCPoints = q;
5368:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5369:     PetscInt fdof;

5371:     PetscSectionGetDof(csection, cpoints[p], &dof);
5372:     if (!dof) continue;
5373:     for (f = 0; f < numFields; ++f) {
5374:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5375:       coffsets[f+1] += fdof;
5376:     }
5377:     numCIndices += dof;
5378:   }
5379:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5380:   /* Row indices */
5381:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5382:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5383:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5384:   for (r = 0, q = 0; r < numSubcells; ++r) {
5385:     /* TODO Map from coarse to fine cells */
5386:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5387:     /* Compress out points not in the section */
5388:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5389:     for (p = 0; p < numFPoints*2; p += 2) {
5390:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5391:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5392:         if (!dof) continue;
5393:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5394:         if (s < q) continue;
5395:         ftotpoints[q*2]   = fpoints[p];
5396:         ftotpoints[q*2+1] = fpoints[p+1];
5397:         ++q;
5398:       }
5399:     }
5400:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5401:   }
5402:   numFPoints = q;
5403:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5404:     PetscInt fdof;

5406:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5407:     if (!dof) continue;
5408:     for (f = 0; f < numFields; ++f) {
5409:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5410:       foffsets[f+1] += fdof;
5411:     }
5412:     numFIndices += dof;
5413:   }
5414:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5416:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
5417:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
5418:   if (numFields) {
5419:     for (p = 0; p < numFPoints*2; p += 2) {
5420:       PetscInt o = ftotpoints[p+1];
5421:       PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);
5422:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
5423:     }
5424:     for (p = 0; p < numCPoints*2; p += 2) {
5425:       PetscInt o = cpoints[p+1];
5426:       PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);
5427:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
5428:     }
5429:   } else {
5430:     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
5431:       PetscInt o = ftotpoints[p+1];
5432:       PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);
5433:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
5434:     }
5435:     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
5436:       PetscInt o = cpoints[p+1];
5437:       PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);
5438:       DMPlexGetIndicesPoint_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
5439:     }
5440:   }
5441:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5442:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5443:   return(0);
5444: }

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

5451:   Input Parameter:
5452: . dm - The DMPlex object

5454:   Output Parameters:
5455: + cMax - The first hybrid cell
5456: . fMax - The first hybrid face
5457: . eMax - The first hybrid edge
5458: - vMax - The first hybrid vertex

5460:   Level: developer

5462: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5463: @*/
5464: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5465: {
5466:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5467:   PetscInt       dim;

5472:   DMGetDimension(dm, &dim);
5473:   if (cMax) *cMax = mesh->hybridPointMax[dim];
5474:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5475:   if (eMax) *eMax = mesh->hybridPointMax[1];
5476:   if (vMax) *vMax = mesh->hybridPointMax[0];
5477:   return(0);
5478: }

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

5485:   Input Parameters:
5486: . dm   - The DMPlex object
5487: . cMax - The first hybrid cell
5488: . fMax - The first hybrid face
5489: . eMax - The first hybrid edge
5490: - vMax - The first hybrid vertex

5492:   Level: developer

5494: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5495: @*/
5496: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5497: {
5498:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5499:   PetscInt       dim;

5504:   DMGetDimension(dm, &dim);
5505:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5506:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5507:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5508:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5509:   return(0);
5510: }

5514: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5515: {
5516:   DM_Plex *mesh = (DM_Plex*) dm->data;

5521:   *cellHeight = mesh->vtkCellHeight;
5522:   return(0);
5523: }

5527: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5528: {
5529:   DM_Plex *mesh = (DM_Plex*) dm->data;

5533:   mesh->vtkCellHeight = cellHeight;
5534:   return(0);
5535: }

5539: /* We can easily have a form that takes an IS instead */
5540: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5541: {
5542:   PetscSection   section, globalSection;
5543:   PetscInt      *numbers, p;

5547:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
5548:   PetscSectionSetChart(section, pStart, pEnd);
5549:   for (p = pStart; p < pEnd; ++p) {
5550:     PetscSectionSetDof(section, p, 1);
5551:   }
5552:   PetscSectionSetUp(section);
5553:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
5554:   PetscMalloc1(pEnd - pStart, &numbers);
5555:   for (p = pStart; p < pEnd; ++p) {
5556:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
5557:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5558:     else                       numbers[p-pStart] += shift;
5559:   }
5560:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
5561:   if (globalSize) {
5562:     PetscLayout layout;
5563:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
5564:     PetscLayoutGetSize(layout, globalSize);
5565:     PetscLayoutDestroy(&layout);
5566:   }
5567:   PetscSectionDestroy(&section);
5568:   PetscSectionDestroy(&globalSection);
5569:   return(0);
5570: }

5574: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5575: {
5576:   PetscInt       cellHeight, cStart, cEnd, cMax;

5580:   DMPlexGetVTKCellHeight(dm, &cellHeight);
5581:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5582:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5583:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5584:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
5585:   return(0);
5586: }

5590: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5591: {
5592:   DM_Plex       *mesh = (DM_Plex*) dm->data;

5597:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
5598:   *globalCellNumbers = mesh->globalCellNumbers;
5599:   return(0);
5600: }

5604: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
5605: {
5606:   PetscInt       vStart, vEnd, vMax;

5611:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5612:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
5613:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
5614:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
5615:   return(0);
5616: }

5620: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5621: {
5622:   DM_Plex       *mesh = (DM_Plex*) dm->data;

5627:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
5628:   *globalVertexNumbers = mesh->globalVertexNumbers;
5629:   return(0);
5630: }

5634: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
5635: {
5636:   IS             nums[4];
5637:   PetscInt       depths[4];
5638:   PetscInt       depth, d, shift = 0;

5643:   DMPlexGetDepth(dm, &depth);
5644:   /* For unstratified meshes use dim instead of depth */
5645:   if (depth < 0) {DMGetDimension(dm, &depth);}
5646:   depths[0] = depth; depths[1] = 0;
5647:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
5648:   for (d = 0; d <= depth; ++d) {
5649:     PetscInt pStart, pEnd, gsize;

5651:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
5652:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
5653:     shift += gsize;
5654:   }
5655:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
5656:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
5657:   return(0);
5658: }

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

5665:   Input Parameters:
5666:   + dm - The DMPlex object

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

5670:   Level: developer

5672: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
5673: @*/
5674: PetscErrorCode DMPlexCheckSymmetry(DM dm)
5675: {
5676:   PetscSection    coneSection, supportSection;
5677:   const PetscInt *cone, *support;
5678:   PetscInt        coneSize, c, supportSize, s;
5679:   PetscInt        pStart, pEnd, p, csize, ssize;
5680:   PetscErrorCode  ierr;

5684:   DMPlexGetConeSection(dm, &coneSection);
5685:   DMPlexGetSupportSection(dm, &supportSection);
5686:   /* Check that point p is found in the support of its cone points, and vice versa */
5687:   DMPlexGetChart(dm, &pStart, &pEnd);
5688:   for (p = pStart; p < pEnd; ++p) {
5689:     DMPlexGetConeSize(dm, p, &coneSize);
5690:     DMPlexGetCone(dm, p, &cone);
5691:     for (c = 0; c < coneSize; ++c) {
5692:       PetscBool dup = PETSC_FALSE;
5693:       PetscInt  d;
5694:       for (d = c-1; d >= 0; --d) {
5695:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
5696:       }
5697:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
5698:       DMPlexGetSupport(dm, cone[c], &support);
5699:       for (s = 0; s < supportSize; ++s) {
5700:         if (support[s] == p) break;
5701:       }
5702:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
5703:         PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);
5704:         for (s = 0; s < coneSize; ++s) {
5705:           PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);
5706:         }
5707:         PetscPrintf(PETSC_COMM_SELF, "\n");
5708:         PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);
5709:         for (s = 0; s < supportSize; ++s) {
5710:           PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);
5711:         }
5712:         PetscPrintf(PETSC_COMM_SELF, "\n");
5713:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not repeatedly found in support of repeated cone point %d", p, cone[c]);
5714:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
5715:       }
5716:     }
5717:     DMPlexGetSupportSize(dm, p, &supportSize);
5718:     DMPlexGetSupport(dm, p, &support);
5719:     for (s = 0; s < supportSize; ++s) {
5720:       DMPlexGetConeSize(dm, support[s], &coneSize);
5721:       DMPlexGetCone(dm, support[s], &cone);
5722:       for (c = 0; c < coneSize; ++c) {
5723:         if (cone[c] == p) break;
5724:       }
5725:       if (c >= coneSize) {
5726:         PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);
5727:         for (c = 0; c < supportSize; ++c) {
5728:           PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);
5729:         }
5730:         PetscPrintf(PETSC_COMM_SELF, "\n");
5731:         PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);
5732:         for (c = 0; c < coneSize; ++c) {
5733:           PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);
5734:         }
5735:         PetscPrintf(PETSC_COMM_SELF, "\n");
5736:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
5737:       }
5738:     }
5739:   }
5740:   PetscSectionGetStorageSize(coneSection, &csize);
5741:   PetscSectionGetStorageSize(supportSection, &ssize);
5742:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
5743:   return(0);
5744: }

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

5751:   Input Parameters:
5752: + dm - The DMPlex object
5753: . isSimplex - Are the cells simplices or tensor products
5754: - cellHeight - Normally 0

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

5758:   Level: developer

5760: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
5761: @*/
5762: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5763: {
5764:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

5769:   DMGetDimension(dm, &dim);
5770:   switch (dim) {
5771:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
5772:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
5773:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
5774:   default:
5775:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
5776:   }
5777:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5778:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5779:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5780:   cMax = cMax >= 0 ? cMax : cEnd;
5781:   for (c = cStart; c < cMax; ++c) {
5782:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

5784:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5785:     for (cl = 0; cl < closureSize*2; cl += 2) {
5786:       const PetscInt p = closure[cl];
5787:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5788:     }
5789:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5790:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
5791:   }
5792:   for (c = cMax; c < cEnd; ++c) {
5793:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

5795:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5796:     for (cl = 0; cl < closureSize*2; cl += 2) {
5797:       const PetscInt p = closure[cl];
5798:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5799:     }
5800:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5801:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has  %d vertices > %d", c, coneSize, numHybridCorners);
5802:   }
5803:   return(0);
5804: }

5808: /*@
5809:   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type

5811:   Input Parameters:
5812: + dm - The DMPlex object
5813: . isSimplex - Are the cells simplices or tensor products
5814: - cellHeight - Normally 0

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

5818:   Level: developer

5820: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
5821: @*/
5822: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5823: {
5824:   PetscInt       pMax[4];
5825:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

5830:   DMGetDimension(dm, &dim);
5831:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5832:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
5833:   for (h = cellHeight; h < dim; ++h) {
5834:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
5835:     for (c = cStart; c < cEnd; ++c) {
5836:       const PetscInt *cone, *ornt, *faces;
5837:       PetscInt        numFaces, faceSize, coneSize,f;
5838:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

5840:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
5841:       DMPlexGetConeSize(dm, c, &coneSize);
5842:       DMPlexGetCone(dm, c, &cone);
5843:       DMPlexGetConeOrientation(dm, c, &ornt);
5844:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5845:       for (cl = 0; cl < closureSize*2; cl += 2) {
5846:         const PetscInt p = closure[cl];
5847:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
5848:       }
5849:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
5850:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces);
5851:       for (f = 0; f < numFaces; ++f) {
5852:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

5854:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
5855:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
5856:           const PetscInt p = fclosure[cl];
5857:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
5858:         }
5859:         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);
5860:         for (v = 0; v < fnumCorners; ++v) {
5861:           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]);
5862:         }
5863:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
5864:       }
5865:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
5866:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
5867:     }
5868:   }
5869:   return(0);
5870: }

5874: /* Pointwise interpolation
5875:      Just code FEM for now
5876:      u^f = I u^c
5877:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
5878:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
5879:      I_{ij} = psi^f_i phi^c_j
5880: */
5881: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
5882: {
5883:   PetscSection   gsc, gsf;
5884:   PetscInt       m, n;
5885:   void          *ctx;
5886:   DM             cdm;
5887:   PetscBool      regular;

5891:   DMGetDefaultGlobalSection(dmFine, &gsf);
5892:   PetscSectionGetConstrainedStorageSize(gsf, &m);
5893:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
5894:   PetscSectionGetConstrainedStorageSize(gsc, &n);

5896:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
5897:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
5898:   MatSetType(*interpolation, dmCoarse->mattype);
5899:   DMGetApplicationContext(dmFine, &ctx);

5901:   DMGetCoarseDM(dmFine, &cdm);
5902:   DMPlexGetRegularRefinement(dmFine, &regular);
5903:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
5904:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
5905:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
5906:   /* Use naive scaling */
5907:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
5908:   return(0);
5909: }

5913: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
5914: {
5916:   VecScatter     ctx;

5919:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
5920:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
5921:   VecScatterDestroy(&ctx);
5922:   return(0);
5923: }

5927: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
5928: {
5929:   PetscSection   section;
5930:   IS            *bcPoints, *bcComps;
5931:   PetscBool     *isFE;
5932:   PetscInt      *bcFields, *numComp, *numDof;
5933:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
5934:   PetscInt       cStart, cEnd, cEndInterior;

5938:   DMGetNumFields(dm, &numFields);
5939:   if (!numFields) return(0);
5940:   /* FE and FV boundary conditions are handled slightly differently */
5941:   PetscMalloc1(numFields, &isFE);
5942:   for (f = 0; f < numFields; ++f) {
5943:     PetscObject  obj;
5944:     PetscClassId id;

5946:     DMGetField(dm, f, &obj);
5947:     PetscObjectGetClassId(obj, &id);
5948:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
5949:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
5950:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
5951:   }
5952:   /* Allocate boundary point storage for FEM boundaries */
5953:   DMPlexGetDepth(dm, &depth);
5954:   DMGetDimension(dm, &dim);
5955:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
5956:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
5957:   PetscDSGetNumBoundary(dm->prob, &numBd);
5958:   for (bd = 0; bd < numBd; ++bd) {
5959:     PetscInt    field;
5960:     PetscBool   isEssential;
5961:     const char  *labelName;
5962:     DMLabel     label;

5964:     PetscDSGetBoundary(dm->prob, bd, &isEssential, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
5965:     DMGetLabel(dm,labelName,&label);
5966:     if (label && isFE[field] && isEssential) ++numBC;
5967:   }
5968:   /* Add ghost cell boundaries for FVM */
5969:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
5970:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
5971:   /* Constrain ghost cells for FV */
5972:   for (f = 0; f < numFields; ++f) {
5973:     PetscInt *newidx, c;

5975:     if (isFE[f] || cEndInterior < 0) continue;
5976:     PetscMalloc1(cEnd-cEndInterior,&newidx);
5977:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
5978:     bcFields[bc] = f;
5979:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
5980:   }
5981:   /* Handle FEM Dirichlet boundaries */
5982:   for (bd = 0; bd < numBd; ++bd) {
5983:     const char     *bdLabel;
5984:     DMLabel         label;
5985:     const PetscInt *comps;
5986:     const PetscInt *values;
5987:     PetscInt        bd2, field, numComps, numValues;
5988:     PetscBool       isEssential, duplicate = PETSC_FALSE;

5990:     PetscDSGetBoundary(dm->prob, bd, &isEssential, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
5991:     DMGetLabel(dm, bdLabel, &label);
5992:     if (!isFE[field] || !label) continue;
5993:     /* Only want to modify label once */
5994:     for (bd2 = 0; bd2 < bd; ++bd2) {
5995:       const char *bdname;
5996:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5997:       PetscStrcmp(bdname, bdLabel, &duplicate);
5998:       if (duplicate) break;
5999:     }
6000:     if (!duplicate && (isFE[field])) {
6001:       /* don't complete cells, which are just present to give orientation to the boundary */
6002:       DMPlexLabelComplete(dm, label);
6003:     }
6004:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6005:     if (isEssential) {
6006:       PetscInt       *newidx;
6007:       PetscInt        n, newn = 0, p, v;

6009:       bcFields[bc] = field;
6010:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6011:       for (v = 0; v < numValues; ++v) {
6012:         IS              tmp;
6013:         const PetscInt *idx;

6015:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6016:         if (!tmp) continue;
6017:         ISGetLocalSize(tmp, &n);
6018:         ISGetIndices(tmp, &idx);
6019:         if (isFE[field]) {
6020:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6021:         } else {
6022:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6023:         }
6024:         ISRestoreIndices(tmp, &idx);
6025:         ISDestroy(&tmp);
6026:       }
6027:       PetscMalloc1(newn,&newidx);
6028:       newn = 0;
6029:       for (v = 0; v < numValues; ++v) {
6030:         IS              tmp;
6031:         const PetscInt *idx;

6033:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6034:         if (!tmp) continue;
6035:         ISGetLocalSize(tmp, &n);
6036:         ISGetIndices(tmp, &idx);
6037:         if (isFE[field]) {
6038:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6039:         } else {
6040:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6041:         }
6042:         ISRestoreIndices(tmp, &idx);
6043:         ISDestroy(&tmp);
6044:       }
6045:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6046:     }
6047:   }
6048:   /* Handle discretization */
6049:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6050:   for (f = 0; f < numFields; ++f) {
6051:     PetscObject obj;

6053:     DMGetField(dm, f, &obj);
6054:     if (isFE[f]) {
6055:       PetscFE         fe = (PetscFE) obj;
6056:       const PetscInt *numFieldDof;
6057:       PetscInt        d;

6059:       PetscFEGetNumComponents(fe, &numComp[f]);
6060:       PetscFEGetNumDof(fe, &numFieldDof);
6061:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6062:     } else {
6063:       PetscFV fv = (PetscFV) obj;

6065:       PetscFVGetNumComponents(fv, &numComp[f]);
6066:       numDof[f*(dim+1)+dim] = numComp[f];
6067:     }
6068:   }
6069:   for (f = 0; f < numFields; ++f) {
6070:     PetscInt d;
6071:     for (d = 1; d < dim; ++d) {
6072:       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.");
6073:     }
6074:   }
6075:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6076:   for (f = 0; f < numFields; ++f) {
6077:     PetscFE     fe;
6078:     const char *name;

6080:     DMGetField(dm, f, (PetscObject *) &fe);
6081:     PetscObjectGetName((PetscObject) fe, &name);
6082:     PetscSectionSetFieldName(section, f, name);
6083:   }
6084:   DMSetDefaultSection(dm, section);
6085:   PetscSectionDestroy(&section);
6086:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6087:   PetscFree3(bcFields,bcPoints,bcComps);
6088:   PetscFree2(numComp,numDof);
6089:   PetscFree(isFE);
6090:   return(0);
6091: }

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

6098:   Input Parameter:
6099: . dm - The DMPlex object

6101:   Output Parameter:
6102: . regular - The flag

6104:   Level: intermediate

6106: .seealso: DMPlexSetRegularRefinement()
6107: @*/
6108: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6109: {
6113:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6114:   return(0);
6115: }

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

6122:   Input Parameters:
6123: + dm - The DMPlex object
6124: - regular - The flag

6126:   Level: intermediate

6128: .seealso: DMPlexGetRegularRefinement()
6129: @*/
6130: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6131: {
6134:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6135:   return(0);
6136: }

6138: /* anchors */
6141: /*@
6142:   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
6143:   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().

6145:   not collective

6147:   Input Parameters:
6148: . dm - The DMPlex object

6150:   Output Parameters:
6151: + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
6152: - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection


6155:   Level: intermediate

6157: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6158: @*/
6159: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6160: {
6161:   DM_Plex *plex = (DM_Plex *)dm->data;

6166:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6167:   if (anchorSection) *anchorSection = plex->anchorSection;
6168:   if (anchorIS) *anchorIS = plex->anchorIS;
6169:   return(0);
6170: }

6174: /*@
6175:   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
6176:   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
6177:   point's degrees of freedom to be a linear combination of other points' degrees of freedom.

6179:   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
6180:   DMGetConstraints() and filling in the entries in the constraint matrix.

6182:   collective on dm

6184:   Input Parameters:
6185: + dm - The DMPlex object
6186: . 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).
6187: - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).

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

6191:   Level: intermediate

6193: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6194: @*/
6195: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6196: {
6197:   DM_Plex        *plex = (DM_Plex *)dm->data;
6198:   PetscMPIInt    result;

6203:   if (anchorSection) {
6205:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6206:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6207:   }
6208:   if (anchorIS) {
6210:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6211:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6212:   }

6214:   PetscObjectReference((PetscObject)anchorSection);
6215:   PetscSectionDestroy(&plex->anchorSection);
6216:   plex->anchorSection = anchorSection;

6218:   PetscObjectReference((PetscObject)anchorIS);
6219:   ISDestroy(&plex->anchorIS);
6220:   plex->anchorIS = anchorIS;

6222: #if defined(PETSC_USE_DEBUG)
6223:   if (anchorIS && anchorSection) {
6224:     PetscInt size, a, pStart, pEnd;
6225:     const PetscInt *anchors;

6227:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6228:     ISGetLocalSize(anchorIS,&size);
6229:     ISGetIndices(anchorIS,&anchors);
6230:     for (a = 0; a < size; a++) {
6231:       PetscInt p;

6233:       p = anchors[a];
6234:       if (p >= pStart && p < pEnd) {
6235:         PetscInt dof;

6237:         PetscSectionGetDof(anchorSection,p,&dof);
6238:         if (dof) {
6239:           PetscErrorCode ierr2;

6241:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6242:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %d cannot be constrained and an anchor",p);
6243:         }
6244:       }
6245:     }
6246:     ISRestoreIndices(anchorIS,&anchors);
6247:   }
6248: #endif
6249:   /* reset the generic constraints */
6250:   DMSetDefaultConstraints(dm,NULL,NULL);
6251:   return(0);
6252: }

6256: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6257: {
6258:   PetscSection anchorSection;
6259:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

6264:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6265:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6266:   PetscSectionGetNumFields(section,&numFields);
6267:   if (numFields) {
6268:     PetscInt f;
6269:     PetscSectionSetNumFields(*cSec,numFields);

6271:     for (f = 0; f < numFields; f++) {
6272:       PetscInt numComp;

6274:       PetscSectionGetFieldComponents(section,f,&numComp);
6275:       PetscSectionSetFieldComponents(*cSec,f,numComp);
6276:     }
6277:   }
6278:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6279:   PetscSectionGetChart(section,&sStart,&sEnd);
6280:   pStart = PetscMax(pStart,sStart);
6281:   pEnd   = PetscMin(pEnd,sEnd);
6282:   pEnd   = PetscMax(pStart,pEnd);
6283:   PetscSectionSetChart(*cSec,pStart,pEnd);
6284:   for (p = pStart; p < pEnd; p++) {
6285:     PetscSectionGetDof(anchorSection,p,&dof);
6286:     if (dof) {
6287:       PetscSectionGetDof(section,p,&dof);
6288:       PetscSectionSetDof(*cSec,p,dof);
6289:       for (f = 0; f < numFields; f++) {
6290:         PetscSectionGetFieldDof(section,p,f,&dof);
6291:         PetscSectionSetFieldDof(*cSec,p,f,dof);
6292:       }
6293:     }
6294:   }
6295:   PetscSectionSetUp(*cSec);
6296:   return(0);
6297: }

6301: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6302: {
6303:   PetscSection aSec;
6304:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6305:   const PetscInt *anchors;
6306:   PetscInt numFields, f;
6307:   IS aIS;

6312:   PetscSectionGetStorageSize(cSec, &m);
6313:   PetscSectionGetStorageSize(section, &n);
6314:   MatCreate(PETSC_COMM_SELF,cMat);
6315:   MatSetSizes(*cMat,m,n,m,n);
6316:   MatSetType(*cMat,MATSEQAIJ);
6317:   DMPlexGetAnchors(dm,&aSec,&aIS);
6318:   ISGetIndices(aIS,&anchors);
6319:   /* cSec will be a subset of aSec and section */
6320:   PetscSectionGetChart(cSec,&pStart,&pEnd);
6321:   PetscMalloc1(m+1,&i);
6322:   i[0] = 0;
6323:   PetscSectionGetNumFields(section,&numFields);
6324:   for (p = pStart; p < pEnd; p++) {
6325:     PetscInt rDof, rOff, r;

6327:     PetscSectionGetDof(aSec,p,&rDof);
6328:     if (!rDof) continue;
6329:     PetscSectionGetOffset(aSec,p,&rOff);
6330:     if (numFields) {
6331:       for (f = 0; f < numFields; f++) {
6332:         annz = 0;
6333:         for (r = 0; r < rDof; r++) {
6334:           a = anchors[rOff + r];
6335:           PetscSectionGetFieldDof(section,a,f,&aDof);
6336:           annz += aDof;
6337:         }
6338:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6339:         PetscSectionGetFieldOffset(cSec,p,f,&off);
6340:         for (q = 0; q < dof; q++) {
6341:           i[off + q + 1] = i[off + q] + annz;
6342:         }
6343:       }
6344:     }
6345:     else {
6346:       annz = 0;
6347:       for (q = 0; q < dof; q++) {
6348:         a = anchors[off + q];
6349:         PetscSectionGetDof(section,a,&aDof);
6350:         annz += aDof;
6351:       }
6352:       PetscSectionGetDof(cSec,p,&dof);
6353:       PetscSectionGetOffset(cSec,p,&off);
6354:       for (q = 0; q < dof; q++) {
6355:         i[off + q + 1] = i[off + q] + annz;
6356:       }
6357:     }
6358:   }
6359:   nnz = i[m];
6360:   PetscMalloc1(nnz,&j);
6361:   offset = 0;
6362:   for (p = pStart; p < pEnd; p++) {
6363:     if (numFields) {
6364:       for (f = 0; f < numFields; f++) {
6365:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6366:         for (q = 0; q < dof; q++) {
6367:           PetscInt rDof, rOff, r;
6368:           PetscSectionGetDof(aSec,p,&rDof);
6369:           PetscSectionGetOffset(aSec,p,&rOff);
6370:           for (r = 0; r < rDof; r++) {
6371:             PetscInt s;

6373:             a = anchors[rOff + r];
6374:             PetscSectionGetFieldDof(section,a,f,&aDof);
6375:             PetscSectionGetFieldOffset(section,a,f,&aOff);
6376:             for (s = 0; s < aDof; s++) {
6377:               j[offset++] = aOff + s;
6378:             }
6379:           }
6380:         }
6381:       }
6382:     }
6383:     else {
6384:       PetscSectionGetDof(cSec,p,&dof);
6385:       for (q = 0; q < dof; q++) {
6386:         PetscInt rDof, rOff, r;
6387:         PetscSectionGetDof(aSec,p,&rDof);
6388:         PetscSectionGetOffset(aSec,p,&rOff);
6389:         for (r = 0; r < rDof; r++) {
6390:           PetscInt s;

6392:           a = anchors[rOff + r];
6393:           PetscSectionGetDof(section,a,&aDof);
6394:           PetscSectionGetOffset(section,a,&aOff);
6395:           for (s = 0; s < aDof; s++) {
6396:             j[offset++] = aOff + s;
6397:           }
6398:         }
6399:       }
6400:     }
6401:   }
6402:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
6403:   PetscFree(i);
6404:   PetscFree(j);
6405:   ISRestoreIndices(aIS,&anchors);
6406:   return(0);
6407: }

6411: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6412: {
6413:   DM_Plex        *plex = (DM_Plex *)dm->data;
6414:   PetscSection   anchorSection, section, cSec;
6415:   Mat            cMat;

6420:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6421:   if (anchorSection) {
6422:     PetscDS  ds;
6423:     PetscInt nf;

6425:     DMGetDefaultSection(dm,&section);
6426:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
6427:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
6428:     DMGetDS(dm,&ds);
6429:     PetscDSGetNumFields(ds,&nf);
6430:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
6431:     DMSetDefaultConstraints(dm,cSec,cMat);
6432:     PetscSectionDestroy(&cSec);
6433:     MatDestroy(&cMat);
6434:   }
6435:   return(0);
6436: }