Actual source code: plex.c

petsc-master 2016-09-28
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) v);  /* viewer drops reference */
 85:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
 86:   } else if (ishdf5) {
 87: #if defined(PETSC_HAVE_HDF5)
 88:     VecView_Plex_Local_HDF5(v, viewer);
 89: #else
 90:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
 91: #endif
 92:   } else {
 93:     if (isseq) {VecView_Seq(v, viewer);}
 94:     else       {VecView_MPI(v, viewer);}
 95:   }
 96:   return(0);
 97: }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

998:   Not collective

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

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

1006:   Level: developer

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

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

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

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

1035:   Not collective

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

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

1044:   Level: beginner

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

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

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

1064:   Not collective

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

1071:   Output Parameters:

1073:   Level: beginner

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

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

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

1094:   Not collective

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

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

1103:   Level: beginner

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

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

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

1124:   Not collective

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

1131:   Output Parameter:

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

1136:   Level: beginner

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

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

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

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

1158:   Not collective

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

1165:   Output Parameter:

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

1170:   Level: beginner

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

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

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

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

1194:   Not collective

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

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

1203:   Level: beginner

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

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

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

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

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

1232:   Not collective

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

1239:   Output Parameter:

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

1244:   Level: beginner

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

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

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

1274:   Not collective

1276:   Input Parameters:
1277: + mesh - The DMPlex
1278: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1286:   Level: beginner

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

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

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

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

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

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

1322:   Not collective

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

1332:   Output Parameter:

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

1337:   Level: beginner

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

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

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

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

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

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

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

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

1411:   Not collective

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

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

1420:   Level: beginner

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

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

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

1441:   Not collective

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

1448:   Output Parameter:

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

1453:   Level: beginner

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

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

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

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

1475:   Not collective

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

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

1484:   Level: beginner

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

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

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

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

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

1513:   Not collective

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

1520:   Output Parameter:

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

1525:   Level: beginner

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

1538:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1539:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1541:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1542:   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1543:   for (c = 0; c < dof; ++c) {
1544:     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);
1545:     mesh->supports[off+c] = support[c];
1546:   }
1547:   return(0);
1548: }

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

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

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

1576:   Not collective

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

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

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

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

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

1597:   Level: beginner

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

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

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

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

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

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

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

1721:   Not collective

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

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

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

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

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

1743:   Level: beginner

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

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

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

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

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

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

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

1875:   Not collective

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

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

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

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

1893:   Level: beginner

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

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

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

1915:   Not collective

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

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

1924:   Level: beginner

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

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

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

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

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

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

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

1978:   Not collective

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

1983:   Output Parameter:

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

1988:   Level: beginner

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

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

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

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

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

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

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

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

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

2053:   Collective on dm

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

2058:   Output Parameter:

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

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

2068:   Level: beginner

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

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

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

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

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

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

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

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

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

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

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

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

2184:   Not Collective

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

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

2195:   Level: intermediate

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

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

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

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

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

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

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

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

2259:   Not Collective

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

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

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

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

2276:   Level: intermediate

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

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

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

2300:   Not Collective

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

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

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

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

2317:   Level: intermediate

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


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

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

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

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

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

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

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

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

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

2409:   Not Collective

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

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

2420:   Level: intermediate

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

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

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

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

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

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

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

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

2484:   Not Collective

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

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

2495:   Level: intermediate

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

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

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

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

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

2525:   Not Collective

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

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

2536:   Level: intermediate

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

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

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


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

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

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

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

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

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

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

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

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

2634:   Not Collective

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

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

2643:   Level: intermediate

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

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


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

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

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

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

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

2772:   Not Collective

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

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

2780:   Level: developer

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

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

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

2802:   Not Collective

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

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

2810:   Level: developer

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

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

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

2835:   Not Collective

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

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

2845:   Level: developer

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

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

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

2878:   Not Collective

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

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

2888:   Level: developer

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

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

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

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

2935:     isFE[f] = PETSC_FALSE;
2936:     if (f >= Nf) continue;
2937:     DMGetField(dm, f, &obj);
2938:     PetscObjectGetClassId(obj, &id);
2939:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
2940:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2941:   }
2942:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
2943:   if (numFields > 0) {
2944:     PetscSectionSetNumFields(*section, numFields);
2945:     if (numComp) {
2946:       for (f = 0; f < numFields; ++f) {
2947:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
2948:         if (isFE[f]) {
2949:           PetscFE           fe;
2950:           PetscDualSpace    dspace;
2951:           const PetscInt    ***perms;
2952:           const PetscScalar ***flips;
2953:           const PetscInt    *numDof;

2955:           DMGetField(dm,f,(PetscObject *) &fe);
2956:           PetscFEGetDualSpace(fe,&dspace);
2957:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
2958:           PetscDualSpaceGetNumDof(dspace,&numDof);
2959:           if (perms || flips) {
2960:             DM               K;
2961:             DMLabel          depthLabel;
2962:             PetscInt         depth, h;
2963:             PetscSectionSym  sym;

2965:             PetscDualSpaceGetDM(dspace,&K);
2966:             DMPlexGetDepthLabel(dm,&depthLabel);
2967:             DMPlexGetDepth(dm,&depth);
2968:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
2969:             for (h = 0; h <= depth; h++) {
2970:               PetscDualSpace    hspace;
2971:               PetscInt          kStart, kEnd;
2972:               PetscInt          kConeSize;
2973:               const PetscInt    **perms0 = NULL;
2974:               const PetscScalar **flips0 = NULL;

2976:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
2977:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
2978:               if (!hspace) continue;
2979:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
2980:               if (perms) perms0 = perms[0];
2981:               if (flips) flips0 = flips[0];
2982:               if (!(perms0 || flips0)) continue;
2983:               DMPlexGetConeSize(K,kStart,&kConeSize);
2984:               if (numComp[f] == 1) {
2985:                 PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
2986:               } else {
2987:                 PetscInt    **fieldPerms = NULL, o;
2988:                 PetscScalar **fieldFlips = NULL;

2990:                 PetscCalloc1(2 * kConeSize,&fieldPerms);
2991:                 PetscCalloc1(2 * kConeSize,&fieldFlips);
2992:                 for (o = -kConeSize; o < kConeSize; o++) {
2993:                   if (perms0 && perms0[o]) {
2994:                     PetscInt r, s;

2996:                     PetscMalloc1(numComp[f] * numDof[depth - h],&fieldPerms[o+kConeSize]);
2997:                     for (r = 0; r < numDof[depth - h]; r++) {
2998:                       for (s = 0; s < numComp[f]; s++) {
2999:                         fieldPerms[o+kConeSize][r * numComp[f] + s] = numComp[f] * perms0[o][r] + s;
3000:                       }
3001:                     }
3002:                   }
3003:                   if (flips0 && flips0[o]) {
3004:                     PetscInt r, s;

3006:                     PetscMalloc1(numComp[f] * numDof[depth - h],&fieldFlips[o+kConeSize]);
3007:                     for (r = 0; r < numDof[depth - h]; r++) {
3008:                       for (s = 0; s < numComp[f]; s++) {
3009:                         fieldFlips[o+kConeSize][r * numComp[f] + s] = flips0[o][r];
3010:                       }
3011:                     }
3012:                   }
3013:                 }
3014:                 PetscSectionSymLabelSetStratum(sym,depth - h,numComp[f] * numDof[depth - h],-kConeSize,kConeSize,PETSC_OWN_POINTER,(const PetscInt **) fieldPerms,(const PetscScalar **)fieldFlips);
3015:               }
3016:             }
3017:             PetscSectionSetFieldSym(*section,f,sym);
3018:             PetscSectionSymDestroy(&sym);
3019:           }
3020:         }
3021:       }
3022:     }
3023:   }
3024:   DMPlexGetChart(dm, &pStart, &pEnd);
3025:   PetscSectionSetChart(*section, pStart, pEnd);
3026:   DMPlexGetDepth(dm, &depth);
3027:   PetscMalloc1(depth+1,&pMax);
3028:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3029:   for (dep = 0; dep <= depth; ++dep) {
3030:     d    = dim == depth ? dep : (!dep ? 0 : dim);
3031:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3032:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3033:     for (p = pStart; p < pEnd; ++p) {
3034:       PetscInt tot = 0;

3036:       for (f = 0; f < numFields; ++f) {
3037:         if (isFE[f] && p >= pMax[dep]) continue;
3038:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3039:         tot += numDof[f*(dim+1)+d];
3040:       }
3041:       PetscSectionSetDof(*section, p, tot);
3042:     }
3043:   }
3044:   PetscFree(pMax);
3045:   PetscFree(isFE);
3046:   return(0);
3047: }

3051: /* Set the number of dof on each point and separate by fields
3052:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3053: */
3054: PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3055: {
3056:   PetscInt       numFields;
3057:   PetscInt       bc;
3058:   PetscSection   aSec;

3062:   PetscSectionGetNumFields(section, &numFields);
3063:   for (bc = 0; bc < numBC; ++bc) {
3064:     PetscInt        field = 0;
3065:     const PetscInt *comp;
3066:     const PetscInt *idx;
3067:     PetscInt        Nc = -1, n, i;

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

3078:       if (numFields) {
3079:         PetscSectionGetFieldDof(section, p, field, &numConst);
3080:       } else {
3081:         PetscSectionGetDof(section, p, &numConst);
3082:       }
3083:       /* If Nc < 0, constrain every dof on the point */
3084:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3085:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3086:       PetscSectionAddConstraintDof(section, p, numConst);
3087:     }
3088:     ISRestoreIndices(bcPoints[bc], &idx);
3089:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3090:   }
3091:   DMPlexGetAnchors(dm, &aSec, NULL);
3092:   if (aSec) {
3093:     PetscInt aStart, aEnd, a;

3095:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3096:     for (a = aStart; a < aEnd; a++) {
3097:       PetscInt dof, f;

3099:       PetscSectionGetDof(aSec, a, &dof);
3100:       if (dof) {
3101:         /* if there are point-to-point constraints, then all dofs are constrained */
3102:         PetscSectionGetDof(section, a, &dof);
3103:         PetscSectionSetConstraintDof(section, a, dof);
3104:         for (f = 0; f < numFields; f++) {
3105:           PetscSectionGetFieldDof(section, a, f, &dof);
3106:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3107:         }
3108:       }
3109:     }
3110:   }
3111:   return(0);
3112: }

3116: /* Set the constrained field indices on each point
3117:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3118: */
3119: PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3120: {
3121:   PetscSection   aSec;
3122:   PetscInt      *indices;
3123:   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;

3127:   PetscSectionGetNumFields(section, &numFields);
3128:   if (!numFields) return(0);
3129:   /* Initialize all field indices to -1 */
3130:   PetscSectionGetChart(section, &pStart, &pEnd);
3131:   PetscSectionGetMaxDof(section, &maxDof);
3132:   PetscMalloc1(maxDof, &indices);
3133:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3134:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3135:   /* Handle BC constraints */
3136:   for (bc = 0; bc < numBC; ++bc) {
3137:     const PetscInt  field = bcField[bc];
3138:     const PetscInt *comp, *idx;
3139:     PetscInt        Nc = -1, n, i;

3141:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3142:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3143:     ISGetLocalSize(bcPoints[bc], &n);
3144:     ISGetIndices(bcPoints[bc], &idx);
3145:     for (i = 0; i < n; ++i) {
3146:       const PetscInt  p = idx[i];
3147:       const PetscInt *find;
3148:       PetscInt        fcdof, c;

3150:       PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3151:       if (Nc < 0) {
3152:         for (d = 0; d < fcdof; ++d) indices[d] = d;
3153:       } else {
3154:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3155:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3156:         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
3157:         PetscSortInt(d+Nc, indices);
3158:         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
3159:       }
3160:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3161:     }
3162:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3163:     ISRestoreIndices(bcPoints[bc], &idx);
3164:   }
3165:   /* Handle anchors */
3166:   DMPlexGetAnchors(dm, &aSec, NULL);
3167:   if (aSec) {
3168:     PetscInt aStart, aEnd, a;

3170:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3171:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3172:     for (a = aStart; a < aEnd; a++) {
3173:       PetscInt dof, fdof, f;

3175:       PetscSectionGetDof(aSec, a, &dof);
3176:       if (dof) {
3177:         /* if there are point-to-point constraints, then all dofs are constrained */
3178:         for (f = 0; f < numFields; f++) {
3179:           PetscSectionGetFieldDof(section, a, f, &fdof);
3180:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3181:         }
3182:       }
3183:     }
3184:   }
3185:   PetscFree(indices);
3186:   return(0);
3187: }

3191: /* Set the constrained indices on each point */
3192: PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3193: {
3194:   PetscInt      *indices;
3195:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3199:   PetscSectionGetNumFields(section, &numFields);
3200:   PetscSectionGetMaxDof(section, &maxDof);
3201:   PetscSectionGetChart(section, &pStart, &pEnd);
3202:   PetscMalloc1(maxDof, &indices);
3203:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3204:   for (p = pStart; p < pEnd; ++p) {
3205:     PetscInt cdof, d;

3207:     PetscSectionGetConstraintDof(section, p, &cdof);
3208:     if (cdof) {
3209:       if (numFields) {
3210:         PetscInt numConst = 0, foff = 0;

3212:         for (f = 0; f < numFields; ++f) {
3213:           const PetscInt *find;
3214:           PetscInt        fcdof, fdof;

3216:           PetscSectionGetFieldDof(section, p, f, &fdof);
3217:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3218:           /* Change constraint numbering from field component to local dof number */
3219:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3220:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3221:           numConst += fcdof;
3222:           foff     += fdof;
3223:         }
3224:         if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
3225:       } else {
3226:         for (d = 0; d < cdof; ++d) indices[d] = d;
3227:       }
3228:       PetscSectionSetConstraintIndices(section, p, indices);
3229:     }
3230:   }
3231:   PetscFree(indices);
3232:   return(0);
3233: }

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

3240:   Not Collective

3242:   Input Parameters:
3243: + dm        - The DMPlex object
3244: . dim       - The spatial dimension of the problem
3245: . numFields - The number of fields in the problem
3246: . numComp   - An array of size numFields that holds the number of components for each field
3247: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3248: . numBC     - The number of boundary conditions
3249: . bcField   - An array of size numBC giving the field number for each boundry condition
3250: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3251: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3252: - perm      - Optional permutation of the chart, or NULL

3254:   Output Parameter:
3255: . section - The PetscSection object

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

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

3262:   Level: developer

3264:   Fortran Notes:
3265:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3267: .keywords: mesh, elements
3268: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3269: @*/
3270: 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)
3271: {
3272:   PetscSection   aSec;

3276:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3277:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3278:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3279:   PetscSectionSetUp(*section);
3280:   DMPlexGetAnchors(dm,&aSec,NULL);
3281:   if (numBC || aSec) {
3282:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3283:     DMPlexCreateSectionBCIndices(dm, *section);
3284:   }
3285:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3286:   return(0);
3287: }

3291: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3292: {
3293:   PetscSection   section, s;
3294:   Mat            m;
3295:   PetscInt       maxHeight;

3299:   DMClone(dm, cdm);
3300:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3301:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3302:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3303:   DMSetDefaultSection(*cdm, section);
3304:   PetscSectionDestroy(&section);
3305:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3306:   MatCreate(PETSC_COMM_SELF, &m);
3307:   DMSetDefaultConstraints(*cdm, s, m);
3308:   PetscSectionDestroy(&s);
3309:   MatDestroy(&m);
3310:   return(0);
3311: }

3315: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3316: {
3317:   DM_Plex *mesh = (DM_Plex*) dm->data;

3321:   if (section) *section = mesh->coneSection;
3322:   return(0);
3323: }

3327: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3328: {
3329:   DM_Plex *mesh = (DM_Plex*) dm->data;

3333:   if (section) *section = mesh->supportSection;
3334:   return(0);
3335: }

3339: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3340: {
3341:   DM_Plex *mesh = (DM_Plex*) dm->data;

3345:   if (cones) *cones = mesh->cones;
3346:   return(0);
3347: }

3351: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3352: {
3353:   DM_Plex *mesh = (DM_Plex*) dm->data;

3357:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3358:   return(0);
3359: }

3361: /******************************** FEM Support **********************************/

3365: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section)
3366: {
3367:   PetscInt      *perm;
3368:   PetscInt       dim, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3372:   if (!section) {DMGetDefaultSection(dm, &section);}
3373:   DMGetDimension(dm, &dim);
3374:   PetscSectionGetNumFields(section, &Nf);
3375:   if (dim <= 1) return(0);
3376:   for (f = 0; f < Nf; ++f) {
3377:     /* An order k SEM disc has k-1 dofs on an edge */
3378:     DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3379:     PetscSectionGetFieldDof(section, eStart, f, &k);
3380:     PetscSectionGetFieldComponents(section, f, &Nc);
3381:     k = k/Nc + 1;
3382:     size += PetscPowInt(k+1, dim)*Nc;
3383:   }
3384:   PetscMalloc1(size, &perm);
3385:   for (f = 0; f < Nf; ++f) {
3386:     switch (dim) {
3387:     case 2:
3388:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3389:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3390:       PetscSectionGetFieldDof(section, eStart, f, &k);
3391:       PetscSectionGetFieldComponents(section, f, &Nc);
3392:       k = k/Nc + 1;
3393:       /* The SEM order is

3395:          v_lb, {e_b}, v_rb,
3396:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3397:          v_lt, reverse {e_t}, v_rt
3398:       */
3399:       {
3400:         const PetscInt of   = 0;
3401:         const PetscInt oeb  = of   + PetscSqr(k-1);
3402:         const PetscInt oer  = oeb  + (k-1);
3403:         const PetscInt oet  = oer  + (k-1);
3404:         const PetscInt oel  = oet  + (k-1);
3405:         const PetscInt ovlb = oel  + (k-1);
3406:         const PetscInt ovrb = ovlb + 1;
3407:         const PetscInt ovrt = ovrb + 1;
3408:         const PetscInt ovlt = ovrt + 1;
3409:         PetscInt       o;

3411:         /* bottom */
3412:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3413:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3414:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3415:         /* middle */
3416:         for (i = 0; i < k-1; ++i) {
3417:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3418:           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;
3419:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3420:         }
3421:         /* top */
3422:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3423:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3424:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3425:         foffset = offset;
3426:       }
3427:       break;
3428:     case 3:
3429:       /* The original hex closure is

3431:          {c,
3432:           f_b, f_t, f_f, f_b, f_r, f_l,
3433:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3434:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3435:       */
3436:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3437:       PetscSectionGetFieldDof(section, eStart, f, &k);
3438:       PetscSectionGetFieldComponents(section, f, &Nc);
3439:       k = k/Nc + 1;
3440:       /* The SEM order is
3441:          Bottom Slice
3442:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3443:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3444:          v_blb, {e_bb}, v_brb,

3446:          Middle Slice (j)
3447:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3448:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3449:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3451:          Top Slice
3452:          v_tlf, {e_tf}, v_trf,
3453:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3454:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3455:       */
3456:       {
3457:         const PetscInt oc    = 0;
3458:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3459:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3460:         const PetscInt off   = oft   + PetscSqr(k-1);
3461:         const PetscInt ofk   = off   + PetscSqr(k-1);
3462:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3463:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3464:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3465:         const PetscInt oebb  = oebl  + (k-1);
3466:         const PetscInt oebr  = oebb  + (k-1);
3467:         const PetscInt oebf  = oebr  + (k-1);
3468:         const PetscInt oetf  = oebf  + (k-1);
3469:         const PetscInt oetr  = oetf  + (k-1);
3470:         const PetscInt oetb  = oetr  + (k-1);
3471:         const PetscInt oetl  = oetb  + (k-1);
3472:         const PetscInt oerf  = oetl  + (k-1);
3473:         const PetscInt oelf  = oerf  + (k-1);
3474:         const PetscInt oelb  = oelf  + (k-1);
3475:         const PetscInt oerb  = oelb  + (k-1);
3476:         const PetscInt ovblf = oerb  + (k-1);
3477:         const PetscInt ovblb = ovblf + 1;
3478:         const PetscInt ovbrb = ovblb + 1;
3479:         const PetscInt ovbrf = ovbrb + 1;
3480:         const PetscInt ovtlf = ovbrf + 1;
3481:         const PetscInt ovtrf = ovtlf + 1;
3482:         const PetscInt ovtrb = ovtrf + 1;
3483:         const PetscInt ovtlb = ovtrb + 1;
3484:         PetscInt       o, n;

3486:         /* Bottom Slice */
3487:         /*   bottom */
3488:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3489:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3490:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3491:         /*   middle */
3492:         for (i = 0; i < k-1; ++i) {
3493:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3494:           for (n = 0; n < k-1; ++n) {o = ofb+n*(k-1)+i; for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;}
3495:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3496:         }
3497:         /*   top */
3498:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3499:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3500:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3502:         /* Middle Slice */
3503:         for (j = 0; j < k-1; ++j) {
3504:           /*   bottom */
3505:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3506:           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;
3507:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3508:           /*   middle */
3509:           for (i = 0; i < k-1; ++i) {
3510:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3511:             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;
3512:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3513:           }
3514:           /*   top */
3515:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3516:           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;
3517:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3518:         }

3520:         /* Top Slice */
3521:         /*   bottom */
3522:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3523:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3524:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3525:         /*   middle */
3526:         for (i = 0; i < k-1; ++i) {
3527:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3528:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3529:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3530:         }
3531:         /*   top */
3532:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3533:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3534:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3536:         foffset = offset;
3537:       }
3538:       break;
3539:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3540:     }
3541:   }
3542:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3543:   /* Check permutation */
3544:   {
3545:     PetscInt *check;

3547:     PetscMalloc1(size, &check);
3548:     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]);}
3549:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3550:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3551:     PetscFree(check);
3552:   }
3553:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3554:   return(0);
3555: }

3559: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3560: {
3561:   PetscDS        prob;
3562:   PetscInt       depth, Nf, h;
3563:   DMLabel        label;

3567:   prob    = dm->prob;
3568:   Nf      = prob->Nf;
3569:   label   = dm->depthLabel;
3570:   *dspace = NULL;
3571:   if (field < Nf) {
3572:     PetscObject disc = prob->disc[field];

3574:     if (disc->classid == PETSCFE_CLASSID) {
3575:       PetscDualSpace dsp;

3577:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3578:       DMLabelGetNumValues(label,&depth);
3579:       DMLabelGetValue(label,point,&h);
3580:       h    = depth - 1 - h;
3581:       if (h) {
3582:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3583:       } else {
3584:         *dspace = dsp;
3585:       }
3586:     }
3587:   }
3588:   return(0);
3589: }


3594: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3595: {
3596:   PetscScalar    *array, *vArray;
3597:   const PetscInt *cone, *coneO;
3598:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3599:   PetscErrorCode  ierr;

3602:   PetscSectionGetChart(section, &pStart, &pEnd);
3603:   DMPlexGetConeSize(dm, point, &numPoints);
3604:   DMPlexGetCone(dm, point, &cone);
3605:   DMPlexGetConeOrientation(dm, point, &coneO);
3606:   if (!values || !*values) {
3607:     if ((point >= pStart) && (point < pEnd)) {
3608:       PetscInt dof;

3610:       PetscSectionGetDof(section, point, &dof);
3611:       size += dof;
3612:     }
3613:     for (p = 0; p < numPoints; ++p) {
3614:       const PetscInt cp = cone[p];
3615:       PetscInt       dof;

3617:       if ((cp < pStart) || (cp >= pEnd)) continue;
3618:       PetscSectionGetDof(section, cp, &dof);
3619:       size += dof;
3620:     }
3621:     if (!values) {
3622:       if (csize) *csize = size;
3623:       return(0);
3624:     }
3625:     DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
3626:   } else {
3627:     array = *values;
3628:   }
3629:   size = 0;
3630:   VecGetArray(v, &vArray);
3631:   if ((point >= pStart) && (point < pEnd)) {
3632:     PetscInt     dof, off, d;
3633:     PetscScalar *varr;

3635:     PetscSectionGetDof(section, point, &dof);
3636:     PetscSectionGetOffset(section, point, &off);
3637:     varr = &vArray[off];
3638:     for (d = 0; d < dof; ++d, ++offset) {
3639:       array[offset] = varr[d];
3640:     }
3641:     size += dof;
3642:   }
3643:   for (p = 0; p < numPoints; ++p) {
3644:     const PetscInt cp = cone[p];
3645:     PetscInt       o  = coneO[p];
3646:     PetscInt       dof, off, d;
3647:     PetscScalar   *varr;

3649:     if ((cp < pStart) || (cp >= pEnd)) continue;
3650:     PetscSectionGetDof(section, cp, &dof);
3651:     PetscSectionGetOffset(section, cp, &off);
3652:     varr = &vArray[off];
3653:     if (o >= 0) {
3654:       for (d = 0; d < dof; ++d, ++offset) {
3655:         array[offset] = varr[d];
3656:       }
3657:     } else {
3658:       for (d = dof-1; d >= 0; --d, ++offset) {
3659:         array[offset] = varr[d];
3660:       }
3661:     }
3662:     size += dof;
3663:   }
3664:   VecRestoreArray(v, &vArray);
3665:   if (!*values) {
3666:     if (csize) *csize = size;
3667:     *values = array;
3668:   } else {
3669:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3670:     *csize = size;
3671:   }
3672:   return(0);
3673: }

3677: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3678: {
3679:   const PetscInt *cla;
3680:   PetscInt       np, *pts = NULL;

3684:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3685:   if (!*clPoints) {
3686:     PetscInt pStart, pEnd, p, q;

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

3704:     PetscSectionGetDof(*clSec, point, &dof);
3705:     PetscSectionGetOffset(*clSec, point, &off);
3706:     ISGetIndices(*clPoints, &cla);
3707:     np   = dof/2;
3708:     pts  = (PetscInt *) &cla[off];
3709:   }
3710:   *numPoints = np;
3711:   *points    = pts;
3712:   *clp       = cla;

3714:   return(0);
3715: }

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

3724:   if (!*clPoints) {
3725:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3726:   } else {
3727:     ISRestoreIndices(*clPoints, clp);
3728:   }
3729:   *numPoints = 0;
3730:   *points    = NULL;
3731:   *clSec     = NULL;
3732:   *clPoints  = NULL;
3733:   *clp       = NULL;
3734:   return(0);
3735: }

3739: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3740: {
3741:   PetscInt          offset = 0, p;
3742:   const PetscInt    **perms = NULL;
3743:   const PetscScalar **flips = NULL;
3744:   PetscErrorCode    ierr;

3747:   *size = 0;
3748:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3749:   for (p = 0; p < numPoints; p++) {
3750:     const PetscInt    point = points[2*p];
3751:     const PetscInt    *perm = perms ? perms[p] : NULL;
3752:     const PetscScalar *flip = flips ? flips[p] : NULL;
3753:     PetscInt          dof, off, d;
3754:     const PetscScalar *varr;

3756:     PetscSectionGetDof(section, point, &dof);
3757:     PetscSectionGetOffset(section, point, &off);
3758:     varr = &vArray[off];
3759:     if (clperm) {
3760:       if (perm) {
3761:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3762:       } else {
3763:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
3764:       }
3765:       if (flip) {
3766:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
3767:       }
3768:     } else {
3769:       if (perm) {
3770:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
3771:       } else {
3772:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
3773:       }
3774:       if (flip) {
3775:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
3776:       }
3777:     }
3778:     offset += dof;
3779:   }
3780:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3781:   *size = offset;
3782:   return(0);
3783: }

3787: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3788: {
3789:   PetscInt          offset = 0, f;
3790:   PetscErrorCode    ierr;

3793:   *size = 0;
3794:   for (f = 0; f < numFields; ++f) {
3795:     PetscInt          p;
3796:     const PetscInt    **perms = NULL;
3797:     const PetscScalar **flips = NULL;

3799:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3800:     for (p = 0; p < numPoints; p++) {
3801:       const PetscInt    point = points[2*p];
3802:       PetscInt          fdof, foff, b;
3803:       const PetscScalar *varr;
3804:       const PetscInt    *perm = perms ? perms[p] : NULL;
3805:       const PetscScalar *flip = flips ? flips[p] : NULL;

3807:       PetscSectionGetFieldDof(section, point, f, &fdof);
3808:       PetscSectionGetFieldOffset(section, point, f, &foff);
3809:       varr = &vArray[foff];
3810:       if (clperm) {
3811:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
3812:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
3813:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
3814:       } else {
3815:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
3816:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
3817:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
3818:       }
3819:       offset += fdof;
3820:     }
3821:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3822:   }
3823:   *size = offset;
3824:   return(0);
3825: }

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

3832:   Not collective

3834:   Input Parameters:
3835: + dm - The DM
3836: . section - The section describing the layout in v, or NULL to use the default section
3837: . v - The local vector
3838: - point - The sieve point in the DM

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

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

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

3850:   Level: intermediate

3852: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3853: @*/
3854: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3855: {
3856:   PetscSection    clSection;
3857:   IS              clPoints;
3858:   PetscScalar    *array, *vArray;
3859:   PetscInt       *points = NULL;
3860:   const PetscInt *clp, *perm;
3861:   PetscInt        depth, numFields, numPoints, size;
3862:   PetscErrorCode  ierr;

3866:   if (!section) {DMGetDefaultSection(dm, &section);}
3869:   DMPlexGetDepth(dm, &depth);
3870:   PetscSectionGetNumFields(section, &numFields);
3871:   if (depth == 1 && numFields < 2) {
3872:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
3873:     return(0);
3874:   }
3875:   /* Get points */
3876:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3877:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
3878:   /* Get array */
3879:   if (!values || !*values) {
3880:     PetscInt asize = 0, dof, p;

3882:     for (p = 0; p < numPoints*2; p += 2) {
3883:       PetscSectionGetDof(section, points[p], &dof);
3884:       asize += dof;
3885:     }
3886:     if (!values) {
3887:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3888:       if (csize) *csize = asize;
3889:       return(0);
3890:     }
3891:     DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
3892:   } else {
3893:     array = *values;
3894:   }
3895:   VecGetArray(v, &vArray);
3896:   /* Get values */
3897:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
3898:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
3899:   /* Cleanup points */
3900:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
3901:   /* Cleanup array */
3902:   VecRestoreArray(v, &vArray);
3903:   if (!*values) {
3904:     if (csize) *csize = size;
3905:     *values = array;
3906:   } else {
3907:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3908:     *csize = size;
3909:   }
3910:   return(0);
3911: }

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

3918:   Not collective

3920:   Input Parameters:
3921: + dm - The DM
3922: . section - The section describing the layout in v, or NULL to use the default section
3923: . v - The local vector
3924: . point - The sieve point in the DM
3925: . csize - The number of values in the closure, or NULL
3926: - values - The array of values, which is a borrowed array and should not be freed

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

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

3934:   Level: intermediate

3936: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3937: @*/
3938: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3939: {
3940:   PetscInt       size = 0;

3944:   /* Should work without recalculating size */
3945:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
3946:   return(0);
3947: }

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

3954: PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
3955: {
3956:   PetscInt        cdof;   /* The number of constraints on this point */
3957:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3958:   PetscScalar    *a;
3959:   PetscInt        off, cind = 0, k;
3960:   PetscErrorCode  ierr;

3963:   PetscSectionGetConstraintDof(section, point, &cdof);
3964:   PetscSectionGetOffset(section, point, &off);
3965:   a    = &array[off];
3966:   if (!cdof || setBC) {
3967:     if (clperm) {
3968:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
3969:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
3970:     } else {
3971:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
3972:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
3973:     }
3974:   } else {
3975:     PetscSectionGetConstraintIndices(section, point, &cdofs);
3976:     if (clperm) {
3977:       if (perm) {for (k = 0; k < dof; ++k) {
3978:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3979:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
3980:         }
3981:       } else {
3982:         for (k = 0; k < dof; ++k) {
3983:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3984:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
3985:         }
3986:       }
3987:     } else {
3988:       if (perm) {
3989:         for (k = 0; k < dof; ++k) {
3990:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3991:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
3992:         }
3993:       } else {
3994:         for (k = 0; k < dof; ++k) {
3995:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3996:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
3997:         }
3998:       }
3999:     }
4000:   }
4001:   return(0);
4002: }

4006: PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
4007: {
4008:   PetscInt        cdof;   /* The number of constraints on this point */
4009:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4010:   PetscScalar    *a;
4011:   PetscInt        off, cind = 0, k;
4012:   PetscErrorCode  ierr;

4015:   PetscSectionGetConstraintDof(section, point, &cdof);
4016:   PetscSectionGetOffset(section, point, &off);
4017:   a    = &array[off];
4018:   if (cdof) {
4019:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4020:     if (clperm) {
4021:       if (perm) {
4022:         for (k = 0; k < dof; ++k) {
4023:           if ((cind < cdof) && (k == cdofs[cind])) {
4024:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4025:             cind++;
4026:           }
4027:         }
4028:       } else {
4029:         for (k = 0; k < dof; ++k) {
4030:           if ((cind < cdof) && (k == cdofs[cind])) {
4031:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4032:             cind++;
4033:           }
4034:         }
4035:       }
4036:     } else {
4037:       if (perm) {
4038:         for (k = 0; k < dof; ++k) {
4039:           if ((cind < cdof) && (k == cdofs[cind])) {
4040:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4041:             cind++;
4042:           }
4043:         }
4044:       } else {
4045:         for (k = 0; k < dof; ++k) {
4046:           if ((cind < cdof) && (k == cdofs[cind])) {
4047:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4048:             cind++;
4049:           }
4050:         }
4051:       }
4052:     }
4053:   }
4054:   return(0);
4055: }

4059: PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, const PetscInt *perm, const PetscScalar *flip, PetscInt f, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4060: {
4061:   PetscScalar    *a;
4062:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4063:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4064:   PetscInt        cind = 0, b;
4065:   PetscErrorCode  ierr;

4068:   PetscSectionGetFieldDof(section, point, f, &fdof);
4069:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4070:   PetscSectionGetFieldOffset(section, point, f, &foff);
4071:   a    = &array[foff];
4072:   if (!fcdof || setBC) {
4073:     if (clperm) {
4074:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4075:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4076:     } else {
4077:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4078:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4079:     }
4080:   } else {
4081:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4082:     if (clperm) {
4083:       if (perm) {
4084:         for (b = 0; b < fdof; b++) {
4085:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4086:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4087:         }
4088:       } else {
4089:         for (b = 0; b < fdof; b++) {
4090:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4091:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4092:         }
4093:       }
4094:     } else {
4095:       if (perm) {
4096:         for (b = 0; b < fdof; b++) {
4097:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4098:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4099:         }
4100:       } else {
4101:         for (b = 0; b < fdof; b++) {
4102:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4103:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4104:         }
4105:       }
4106:     }
4107:   }
4108:   *offset += fdof;
4109:   return(0);
4110: }

4114: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4115: {
4116:   PetscScalar    *a;
4117:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4118:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4119:   PetscInt        cind = 0, b;
4120:   PetscErrorCode  ierr;

4123:   PetscSectionGetFieldDof(section, point, f, &fdof);
4124:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4125:   PetscSectionGetFieldOffset(section, point, f, &foff);
4126:   a    = &array[foff];
4127:   if (fcdof) {
4128:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4129:     if (clperm) {
4130:       if (perm) {
4131:         for (b = 0; b < fdof; b++) {
4132:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4133:             fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4134:             ++cind;
4135:           }
4136:         }
4137:       } else {
4138:         for (b = 0; b < fdof; b++) {
4139:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4140:             fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4141:             ++cind;
4142:           }
4143:         }
4144:       }
4145:     } else {
4146:       if (perm) {
4147:         for (b = 0; b < fdof; b++) {
4148:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4149:             fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4150:             ++cind;
4151:           }
4152:         }
4153:       } else {
4154:         for (b = 0; b < fdof; b++) {
4155:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4156:             fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4157:             ++cind;
4158:           }
4159:         }
4160:       }
4161:     }
4162:   }
4163:   *offset += fdof;
4164:   return(0);
4165: }

4169: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4170: {
4171:   PetscScalar    *array;
4172:   const PetscInt *cone, *coneO;
4173:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4174:   PetscErrorCode  ierr;

4177:   PetscSectionGetChart(section, &pStart, &pEnd);
4178:   DMPlexGetConeSize(dm, point, &numPoints);
4179:   DMPlexGetCone(dm, point, &cone);
4180:   DMPlexGetConeOrientation(dm, point, &coneO);
4181:   VecGetArray(v, &array);
4182:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4183:     const PetscInt cp = !p ? point : cone[p-1];
4184:     const PetscInt o  = !p ? 0     : coneO[p-1];

4186:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4187:     PetscSectionGetDof(section, cp, &dof);
4188:     /* ADD_VALUES */
4189:     {
4190:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4191:       PetscScalar    *a;
4192:       PetscInt        cdof, coff, cind = 0, k;

4194:       PetscSectionGetConstraintDof(section, cp, &cdof);
4195:       PetscSectionGetOffset(section, cp, &coff);
4196:       a    = &array[coff];
4197:       if (!cdof) {
4198:         if (o >= 0) {
4199:           for (k = 0; k < dof; ++k) {
4200:             a[k] += values[off+k];
4201:           }
4202:         } else {
4203:           for (k = 0; k < dof; ++k) {
4204:             a[k] += values[off+dof-k-1];
4205:           }
4206:         }
4207:       } else {
4208:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4209:         if (o >= 0) {
4210:           for (k = 0; k < dof; ++k) {
4211:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4212:             a[k] += values[off+k];
4213:           }
4214:         } else {
4215:           for (k = 0; k < dof; ++k) {
4216:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4217:             a[k] += values[off+dof-k-1];
4218:           }
4219:         }
4220:       }
4221:     }
4222:   }
4223:   VecRestoreArray(v, &array);
4224:   return(0);
4225: }

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

4232:   Not collective

4234:   Input Parameters:
4235: + dm - The DM
4236: . section - The section describing the layout in v, or NULL to use the default section
4237: . v - The local vector
4238: . point - The sieve point in the DM
4239: . values - The array of values
4240: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

4245:   Level: intermediate

4247: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4248: @*/
4249: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4250: {
4251:   PetscSection    clSection;
4252:   IS              clPoints;
4253:   PetscScalar    *array;
4254:   PetscInt       *points = NULL;
4255:   const PetscInt *clp, *clperm;
4256:   PetscInt        depth, numFields, numPoints, p;
4257:   PetscErrorCode  ierr;

4261:   if (!section) {DMGetDefaultSection(dm, &section);}
4264:   DMPlexGetDepth(dm, &depth);
4265:   PetscSectionGetNumFields(section, &numFields);
4266:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4267:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4268:     return(0);
4269:   }
4270:   /* Get points */
4271:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4272:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4273:   /* Get array */
4274:   VecGetArray(v, &array);
4275:   /* Get values */
4276:   if (numFields > 0) {
4277:     PetscInt offset = 0, f;
4278:     for (f = 0; f < numFields; ++f) {
4279:       const PetscInt    **perms = NULL;
4280:       const PetscScalar **flips = NULL;

4282:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4283:       switch (mode) {
4284:       case INSERT_VALUES:
4285:         for (p = 0; p < numPoints; p++) {
4286:           const PetscInt    point = points[2*p];
4287:           const PetscInt    *perm = perms ? perms[p] : NULL;
4288:           const PetscScalar *flip = flips ? flips[p] : NULL;
4289:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4290:         } break;
4291:       case INSERT_ALL_VALUES:
4292:         for (p = 0; p < numPoints; p++) {
4293:           const PetscInt    point = points[2*p];
4294:           const PetscInt    *perm = perms ? perms[p] : NULL;
4295:           const PetscScalar *flip = flips ? flips[p] : NULL;
4296:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4297:         } break;
4298:       case INSERT_BC_VALUES:
4299:         for (p = 0; p < numPoints; p++) {
4300:           const PetscInt    point = points[2*p];
4301:           const PetscInt    *perm = perms ? perms[p] : NULL;
4302:           const PetscScalar *flip = flips ? flips[p] : NULL;
4303:           updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4304:         } break;
4305:       case ADD_VALUES:
4306:         for (p = 0; p < numPoints; p++) {
4307:           const PetscInt    point = points[2*p];
4308:           const PetscInt    *perm = perms ? perms[p] : NULL;
4309:           const PetscScalar *flip = flips ? flips[p] : NULL;
4310:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4311:         } break;
4312:       case ADD_ALL_VALUES:
4313:         for (p = 0; p < numPoints; p++) {
4314:           const PetscInt    point = points[2*p];
4315:           const PetscInt    *perm = perms ? perms[p] : NULL;
4316:           const PetscScalar *flip = flips ? flips[p] : NULL;
4317:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4318:         } break;
4319:       case ADD_BC_VALUES:
4320:         for (p = 0; p < numPoints; p++) {
4321:           const PetscInt    point = points[2*p];
4322:           const PetscInt    *perm = perms ? perms[p] : NULL;
4323:           const PetscScalar *flip = flips ? flips[p] : NULL;
4324:           updatePointFieldsBC_private(section, point, perm, flip, f, add, clperm, values, &offset, array);
4325:         } break;
4326:       default:
4327:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4328:       }
4329:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4330:     }
4331:   } else {
4332:     PetscInt dof, off;
4333:     const PetscInt    **perms = NULL;
4334:     const PetscScalar **flips = NULL;

4336:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4337:     switch (mode) {
4338:     case INSERT_VALUES:
4339:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4340:         const PetscInt    point = points[2*p];
4341:         const PetscInt    *perm = perms ? perms[p] : NULL;
4342:         const PetscScalar *flip = flips ? flips[p] : NULL;
4343:         PetscSectionGetDof(section, point, &dof);
4344:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4345:       } break;
4346:     case INSERT_ALL_VALUES:
4347:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4348:         const PetscInt    point = points[2*p];
4349:         const PetscInt    *perm = perms ? perms[p] : NULL;
4350:         const PetscScalar *flip = flips ? flips[p] : NULL;
4351:         PetscSectionGetDof(section, point, &dof);
4352:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4353:       } break;
4354:     case INSERT_BC_VALUES:
4355:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4356:         const PetscInt    point = points[2*p];
4357:         const PetscInt    *perm = perms ? perms[p] : NULL;
4358:         const PetscScalar *flip = flips ? flips[p] : NULL;
4359:         PetscSectionGetDof(section, point, &dof);
4360:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4361:       } break;
4362:     case ADD_VALUES:
4363:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4364:         const PetscInt    point = points[2*p];
4365:         const PetscInt    *perm = perms ? perms[p] : NULL;
4366:         const PetscScalar *flip = flips ? flips[p] : NULL;
4367:         PetscSectionGetDof(section, point, &dof);
4368:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4369:       } break;
4370:     case ADD_ALL_VALUES:
4371:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4372:         const PetscInt    point = points[2*p];
4373:         const PetscInt    *perm = perms ? perms[p] : NULL;
4374:         const PetscScalar *flip = flips ? flips[p] : NULL;
4375:         PetscSectionGetDof(section, point, &dof);
4376:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4377:       } break;
4378:     case ADD_BC_VALUES:
4379:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4380:         const PetscInt    point = points[2*p];
4381:         const PetscInt    *perm = perms ? perms[p] : NULL;
4382:         const PetscScalar *flip = flips ? flips[p] : NULL;
4383:         PetscSectionGetDof(section, point, &dof);
4384:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4385:       } break;
4386:     default:
4387:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4388:     }
4389:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4390:   }
4391:   /* Cleanup points */
4392:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4393:   /* Cleanup array */
4394:   VecRestoreArray(v, &array);
4395:   return(0);
4396: }

4400: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
4401: {
4402:   PetscSection      clSection;
4403:   IS                clPoints;
4404:   PetscScalar       *array;
4405:   PetscInt          *points = NULL;
4406:   const PetscInt    *clp, *perm;
4407:   PetscInt          numFields, numPoints, p;
4408:   PetscInt          offset = 0, f;
4409:   PetscErrorCode    ierr;

4413:   if (!section) {DMGetDefaultSection(dm, &section);}
4416:   PetscSectionGetNumFields(section, &numFields);
4417:   /* Get points */
4418:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4419:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4420:   /* Get array */
4421:   VecGetArray(v, &array);
4422:   /* Get values */
4423:   for (f = 0; f < numFields; ++f) {
4424:     const PetscInt    **perms = NULL;
4425:     const PetscScalar **flips = NULL;

4427:     if (!fieldActive[f]) {
4428:       for (p = 0; p < numPoints*2; p += 2) {
4429:         PetscInt fdof;
4430:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4431:         offset += fdof;
4432:       }
4433:       continue;
4434:     }
4435:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4436:     switch (mode) {
4437:     case INSERT_VALUES:
4438:       for (p = 0; p < numPoints; p++) {
4439:         const PetscInt    point = points[2*p];
4440:         const PetscInt    *perm = perms ? perms[p] : NULL;
4441:         const PetscScalar *flip = flips ? flips[p] : NULL;
4442:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, perm, values, &offset, array);
4443:       } break;
4444:     case INSERT_ALL_VALUES:
4445:       for (p = 0; p < numPoints; p++) {
4446:         const PetscInt    point = points[2*p];
4447:         const PetscInt    *perm = perms ? perms[p] : NULL;
4448:         const PetscScalar *flip = flips ? flips[p] : NULL;
4449:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, perm, values, &offset, array);
4450:         } break;
4451:     case INSERT_BC_VALUES:
4452:       for (p = 0; p < numPoints; p++) {
4453:         const PetscInt    point = points[2*p];
4454:         const PetscInt    *perm = perms ? perms[p] : NULL;
4455:         const PetscScalar *flip = flips ? flips[p] : NULL;
4456:         updatePointFieldsBC_private(section, point, perm, flip, f, insert, perm, values, &offset, array);
4457:       } break;
4458:     case ADD_VALUES:
4459:       for (p = 0; p < numPoints; p++) {
4460:         const PetscInt    point = points[2*p];
4461:         const PetscInt    *perm = perms ? perms[p] : NULL;
4462:         const PetscScalar *flip = flips ? flips[p] : NULL;
4463:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, perm, values, &offset, array);
4464:       } break;
4465:     case ADD_ALL_VALUES:
4466:       for (p = 0; p < numPoints; p++) {
4467:         const PetscInt    point = points[2*p];
4468:         const PetscInt    *perm = perms ? perms[p] : NULL;
4469:         const PetscScalar *flip = flips ? flips[p] : NULL;
4470:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, perm, values, &offset, array);
4471:       } break;
4472:     default:
4473:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4474:     }
4475:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4476:   }
4477:   /* Cleanup points */
4478:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4479:   /* Cleanup array */
4480:   VecRestoreArray(v, &array);
4481:   return(0);
4482: }

4486: PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4487: {
4488:   PetscMPIInt    rank;
4489:   PetscInt       i, j;

4493:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4494:   PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);
4495:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4496:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4497:   numCIndices = numCIndices ? numCIndices : numRIndices;
4498:   for (i = 0; i < numRIndices; i++) {
4499:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4500:     for (j = 0; j < numCIndices; j++) {
4501: #if defined(PETSC_USE_COMPLEX)
4502:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4503: #else
4504:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4505: #endif
4506:     }
4507:     PetscViewerASCIIPrintf(viewer, "\n");
4508:   }
4509:   return(0);
4510: }

4514: /* . off - The global offset of this point */
4515: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4516: {
4517:   PetscInt        dof;    /* The number of unknowns on this point */
4518:   PetscInt        cdof;   /* The number of constraints on this point */
4519:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4520:   PetscInt        cind = 0, k;
4521:   PetscErrorCode  ierr;

4524:   PetscSectionGetDof(section, point, &dof);
4525:   PetscSectionGetConstraintDof(section, point, &cdof);
4526:   if (!cdof || setBC) {
4527:     if (perm) {
4528:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4529:     } else {
4530:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4531:     }
4532:   } else {
4533:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4534:     if (perm) {
4535:       for (k = 0; k < dof; ++k) {
4536:         if ((cind < cdof) && (k == cdofs[cind])) {
4537:           /* Insert check for returning constrained indices */
4538:           indices[*loff+perm[k]] = -(off+k+1);
4539:           ++cind;
4540:         } else {
4541:           indices[*loff+perm[k]] = off+k-cind;
4542:         }
4543:       }
4544:     } else {
4545:       for (k = 0; k < dof; ++k) {
4546:         if ((cind < cdof) && (k == cdofs[cind])) {
4547:           /* Insert check for returning constrained indices */
4548:           indices[*loff+k] = -(off+k+1);
4549:           ++cind;
4550:         } else {
4551:           indices[*loff+k] = off+k-cind;
4552:         }
4553:       }
4554:     }
4555:   }
4556:   *loff += dof;
4557:   return(0);
4558: }

4562: /* . off - The global offset of this point */
4563: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4564: {
4565:   PetscInt       numFields, foff, f;

4569:   PetscSectionGetNumFields(section, &numFields);
4570:   for (f = 0, foff = 0; f < numFields; ++f) {
4571:     PetscInt        fdof, cfdof;
4572:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4573:     PetscInt        cind = 0, b;
4574:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4576:     PetscSectionGetFieldDof(section, point, f, &fdof);
4577:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4578:     if (!cfdof || setBC) {
4579:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4580:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4581:     } else {
4582:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4583:       if (perm) {
4584:         for (b = 0; b < fdof; b++) {
4585:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4586:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4587:             ++cind;
4588:           } else {
4589:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4590:           }
4591:         }
4592:       } else {
4593:         for (b = 0; b < fdof; b++) {
4594:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4595:             indices[foffs[f]+b] = -(off+foff+b+1);
4596:             ++cind;
4597:           } else {
4598:             indices[foffs[f]+b] = off+foff+b-cind;
4599:           }
4600:         }
4601:       }
4602:     }
4603:     foff     += (setBC ? fdof : (fdof - cfdof));
4604:     foffs[f] += fdof;
4605:   }
4606:   return(0);
4607: }

4611: PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft)
4612: {
4613:   Mat             cMat;
4614:   PetscSection    aSec, cSec;
4615:   IS              aIS;
4616:   PetscInt        aStart = -1, aEnd = -1;
4617:   const PetscInt  *anchors;
4618:   PetscInt        numFields, f, p, q, newP = 0;
4619:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4620:   PetscInt        *newPoints, *indices, *newIndices;
4621:   PetscInt        maxAnchor, maxDof;
4622:   PetscInt        newOffsets[32];
4623:   PetscInt        *pointMatOffsets[32];
4624:   PetscInt        *newPointOffsets[32];
4625:   PetscScalar     *pointMat[32];
4626:   PetscScalar     *newValues=NULL,*tmpValues;
4627:   PetscBool       anyConstrained = PETSC_FALSE;
4628:   PetscErrorCode  ierr;

4633:   PetscSectionGetNumFields(section, &numFields);

4635:   DMPlexGetAnchors(dm,&aSec,&aIS);
4636:   /* if there are point-to-point constraints */
4637:   if (aSec) {
4638:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4639:     ISGetIndices(aIS,&anchors);
4640:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4641:     /* figure out how many points are going to be in the new element matrix
4642:      * (we allow double counting, because it's all just going to be summed
4643:      * into the global matrix anyway) */
4644:     for (p = 0; p < 2*numPoints; p+=2) {
4645:       PetscInt b    = points[p];
4646:       PetscInt bDof = 0, bSecDof;

4648:       PetscSectionGetDof(section,b,&bSecDof);
4649:       if (!bSecDof) {
4650:         continue;
4651:       }
4652:       if (b >= aStart && b < aEnd) {
4653:         PetscSectionGetDof(aSec,b,&bDof);
4654:       }
4655:       if (bDof) {
4656:         /* this point is constrained */
4657:         /* it is going to be replaced by its anchors */
4658:         PetscInt bOff, q;

4660:         anyConstrained = PETSC_TRUE;
4661:         newNumPoints  += bDof;
4662:         PetscSectionGetOffset(aSec,b,&bOff);
4663:         for (q = 0; q < bDof; q++) {
4664:           PetscInt a = anchors[bOff + q];
4665:           PetscInt aDof;

4667:           PetscSectionGetDof(section,a,&aDof);
4668:           newNumIndices += aDof;
4669:           for (f = 0; f < numFields; ++f) {
4670:             PetscInt fDof;

4672:             PetscSectionGetFieldDof(section, a, f, &fDof);
4673:             newOffsets[f+1] += fDof;
4674:           }
4675:         }
4676:       }
4677:       else {
4678:         /* this point is not constrained */
4679:         newNumPoints++;
4680:         newNumIndices += bSecDof;
4681:         for (f = 0; f < numFields; ++f) {
4682:           PetscInt fDof;

4684:           PetscSectionGetFieldDof(section, b, f, &fDof);
4685:           newOffsets[f+1] += fDof;
4686:         }
4687:       }
4688:     }
4689:   }
4690:   if (!anyConstrained) {
4691:     if (outNumPoints)  *outNumPoints  = 0;
4692:     if (outNumIndices) *outNumIndices = 0;
4693:     if (outPoints)     *outPoints     = NULL;
4694:     if (outValues)     *outValues     = NULL;
4695:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4696:     return(0);
4697:   }

4699:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4700:   if (outNumIndices) *outNumIndices = newNumIndices;

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

4704:   if (!outPoints && !outValues) {
4705:     if (offsets) {
4706:       for (f = 0; f <= numFields; f++) {
4707:         offsets[f] = newOffsets[f];
4708:       }
4709:     }
4710:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4711:     return(0);
4712:   }

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

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

4718:   /* workspaces */
4719:   if (numFields) {
4720:     for (f = 0; f < numFields; f++) {
4721:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
4722:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
4723:     }
4724:   }
4725:   else {
4726:     DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
4727:     DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);
4728:   }

4730:   /* get workspaces for the point-to-point matrices */
4731:   if (numFields) {
4732:     PetscInt totalOffset, totalMatOffset;

4734:     for (p = 0; p < numPoints; p++) {
4735:       PetscInt b    = points[2*p];
4736:       PetscInt bDof = 0, bSecDof;

4738:       PetscSectionGetDof(section,b,&bSecDof);
4739:       if (!bSecDof) {
4740:         for (f = 0; f < numFields; f++) {
4741:           newPointOffsets[f][p + 1] = 0;
4742:           pointMatOffsets[f][p + 1] = 0;
4743:         }
4744:         continue;
4745:       }
4746:       if (b >= aStart && b < aEnd) {
4747:         PetscSectionGetDof(aSec, b, &bDof);
4748:       }
4749:       if (bDof) {
4750:         for (f = 0; f < numFields; f++) {
4751:           PetscInt fDof, q, bOff, allFDof = 0;

4753:           PetscSectionGetFieldDof(section, b, f, &fDof);
4754:           PetscSectionGetOffset(aSec, b, &bOff);
4755:           for (q = 0; q < bDof; q++) {
4756:             PetscInt a = anchors[bOff + q];
4757:             PetscInt aFDof;

4759:             PetscSectionGetFieldDof(section, a, f, &aFDof);
4760:             allFDof += aFDof;
4761:           }
4762:           newPointOffsets[f][p+1] = allFDof;
4763:           pointMatOffsets[f][p+1] = fDof * allFDof;
4764:         }
4765:       }
4766:       else {
4767:         for (f = 0; f < numFields; f++) {
4768:           PetscInt fDof;

4770:           PetscSectionGetFieldDof(section, b, f, &fDof);
4771:           newPointOffsets[f][p+1] = fDof;
4772:           pointMatOffsets[f][p+1] = 0;
4773:         }
4774:       }
4775:     }
4776:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
4777:       newPointOffsets[f][0] = totalOffset;
4778:       pointMatOffsets[f][0] = totalMatOffset;
4779:       for (p = 0; p < numPoints; p++) {
4780:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4781:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4782:       }
4783:       totalOffset    = newPointOffsets[f][numPoints];
4784:       totalMatOffset = pointMatOffsets[f][numPoints];
4785:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
4786:     }
4787:   }
4788:   else {
4789:     for (p = 0; p < numPoints; p++) {
4790:       PetscInt b    = points[2*p];
4791:       PetscInt bDof = 0, bSecDof;

4793:       PetscSectionGetDof(section,b,&bSecDof);
4794:       if (!bSecDof) {
4795:         newPointOffsets[0][p + 1] = 0;
4796:         pointMatOffsets[0][p + 1] = 0;
4797:         continue;
4798:       }
4799:       if (b >= aStart && b < aEnd) {
4800:         PetscSectionGetDof(aSec, b, &bDof);
4801:       }
4802:       if (bDof) {
4803:         PetscInt bOff, q, allDof = 0;

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

4809:           PetscSectionGetDof(section, a, &aDof);
4810:           allDof += aDof;
4811:         }
4812:         newPointOffsets[0][p+1] = allDof;
4813:         pointMatOffsets[0][p+1] = bSecDof * allDof;
4814:       }
4815:       else {
4816:         newPointOffsets[0][p+1] = bSecDof;
4817:         pointMatOffsets[0][p+1] = 0;
4818:       }
4819:     }
4820:     newPointOffsets[0][0] = 0;
4821:     pointMatOffsets[0][0] = 0;
4822:     for (p = 0; p < numPoints; p++) {
4823:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4824:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4825:     }
4826:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
4827:   }

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

4832:   /* get the point-to-point matrices; construct newPoints */
4833:   PetscSectionGetMaxDof(aSec, &maxAnchor);
4834:   PetscSectionGetMaxDof(section, &maxDof);
4835:   DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);
4836:   DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
4837:   if (numFields) {
4838:     for (p = 0, newP = 0; p < numPoints; p++) {
4839:       PetscInt b    = points[2*p];
4840:       PetscInt o    = points[2*p+1];
4841:       PetscInt bDof = 0, bSecDof;

4843:       PetscSectionGetDof(section, b, &bSecDof);
4844:       if (!bSecDof) {
4845:         continue;
4846:       }
4847:       if (b >= aStart && b < aEnd) {
4848:         PetscSectionGetDof(aSec, b, &bDof);
4849:       }
4850:       if (bDof) {
4851:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

4853:         fStart[0] = 0;
4854:         fEnd[0]   = 0;
4855:         for (f = 0; f < numFields; f++) {
4856:           PetscInt fDof;

4858:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
4859:           fStart[f+1] = fStart[f] + fDof;
4860:           fEnd[f+1]   = fStart[f+1];
4861:         }
4862:         PetscSectionGetOffset(cSec, b, &bOff);
4863:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

4865:         fAnchorStart[0] = 0;
4866:         fAnchorEnd[0]   = 0;
4867:         for (f = 0; f < numFields; f++) {
4868:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

4870:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4871:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4872:         }
4873:         PetscSectionGetOffset(aSec, b, &bOff);
4874:         for (q = 0; q < bDof; q++) {
4875:           PetscInt a = anchors[bOff + q], aOff;

4877:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4878:           newPoints[2*(newP + q)]     = a;
4879:           newPoints[2*(newP + q) + 1] = 0;
4880:           PetscSectionGetOffset(section, a, &aOff);
4881:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
4882:         }
4883:         newP += bDof;

4885:         if (outValues) {
4886:           /* get the point-to-point submatrix */
4887:           for (f = 0; f < numFields; f++) {
4888:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
4889:           }
4890:         }
4891:       }
4892:       else {
4893:         newPoints[2 * newP]     = b;
4894:         newPoints[2 * newP + 1] = o;
4895:         newP++;
4896:       }
4897:     }
4898:   } else {
4899:     for (p = 0; p < numPoints; p++) {
4900:       PetscInt b    = points[2*p];
4901:       PetscInt o    = points[2*p+1];
4902:       PetscInt bDof = 0, bSecDof;

4904:       PetscSectionGetDof(section, b, &bSecDof);
4905:       if (!bSecDof) {
4906:         continue;
4907:       }
4908:       if (b >= aStart && b < aEnd) {
4909:         PetscSectionGetDof(aSec, b, &bDof);
4910:       }
4911:       if (bDof) {
4912:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

4923:           newPoints[2*(newP + q)]     = a;
4924:           newPoints[2*(newP + q) + 1] = 0;
4925:           PetscSectionGetOffset(section, a, &aOff);
4926:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
4927:         }
4928:         newP += bDof;

4930:         /* get the point-to-point submatrix */
4931:         if (outValues) {
4932:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
4933:         }
4934:       }
4935:       else {
4936:         newPoints[2 * newP]     = b;
4937:         newPoints[2 * newP + 1] = o;
4938:         newP++;
4939:       }
4940:     }
4941:   }

4943:   if (outValues) {
4944:     DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
4945:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
4946:     /* multiply constraints on the right */
4947:     if (numFields) {
4948:       for (f = 0; f < numFields; f++) {
4949:         PetscInt oldOff = offsets[f];

4951:         for (p = 0; p < numPoints; p++) {
4952:           PetscInt cStart = newPointOffsets[f][p];
4953:           PetscInt b      = points[2 * p];
4954:           PetscInt c, r, k;
4955:           PetscInt dof;

4957:           PetscSectionGetFieldDof(section,b,f,&dof);
4958:           if (!dof) {
4959:             continue;
4960:           }
4961:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4962:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
4963:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

4965:             for (r = 0; r < numIndices; r++) {
4966:               for (c = 0; c < nCols; c++) {
4967:                 for (k = 0; k < dof; k++) {
4968:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
4969:                 }
4970:               }
4971:             }
4972:           }
4973:           else {
4974:             /* copy this column as is */
4975:             for (r = 0; r < numIndices; r++) {
4976:               for (c = 0; c < dof; c++) {
4977:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4978:               }
4979:             }
4980:           }
4981:           oldOff += dof;
4982:         }
4983:       }
4984:     }
4985:     else {
4986:       PetscInt oldOff = 0;
4987:       for (p = 0; p < numPoints; p++) {
4988:         PetscInt cStart = newPointOffsets[0][p];
4989:         PetscInt b      = points[2 * p];
4990:         PetscInt c, r, k;
4991:         PetscInt dof;

4993:         PetscSectionGetDof(section,b,&dof);
4994:         if (!dof) {
4995:           continue;
4996:         }
4997:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
4998:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
4999:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5001:           for (r = 0; r < numIndices; r++) {
5002:             for (c = 0; c < nCols; c++) {
5003:               for (k = 0; k < dof; k++) {
5004:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5005:               }
5006:             }
5007:           }
5008:         }
5009:         else {
5010:           /* copy this column as is */
5011:           for (r = 0; r < numIndices; r++) {
5012:             for (c = 0; c < dof; c++) {
5013:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5014:             }
5015:           }
5016:         }
5017:         oldOff += dof;
5018:       }
5019:     }

5021:     if (multiplyLeft) {
5022:       DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5023:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5024:       /* multiply constraints transpose on the left */
5025:       if (numFields) {
5026:         for (f = 0; f < numFields; f++) {
5027:           PetscInt oldOff = offsets[f];

5029:           for (p = 0; p < numPoints; p++) {
5030:             PetscInt rStart = newPointOffsets[f][p];
5031:             PetscInt b      = points[2 * p];
5032:             PetscInt c, r, k;
5033:             PetscInt dof;

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

5040:               for (r = 0; r < nRows; r++) {
5041:                 for (c = 0; c < newNumIndices; c++) {
5042:                   for (k = 0; k < dof; k++) {
5043:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5044:                   }
5045:                 }
5046:               }
5047:             }
5048:             else {
5049:               /* copy this row as is */
5050:               for (r = 0; r < dof; r++) {
5051:                 for (c = 0; c < newNumIndices; c++) {
5052:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5053:                 }
5054:               }
5055:             }
5056:             oldOff += dof;
5057:           }
5058:         }
5059:       }
5060:       else {
5061:         PetscInt oldOff = 0;

5063:         for (p = 0; p < numPoints; p++) {
5064:           PetscInt rStart = newPointOffsets[0][p];
5065:           PetscInt b      = points[2 * p];
5066:           PetscInt c, r, k;
5067:           PetscInt dof;

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

5074:             for (r = 0; r < nRows; r++) {
5075:               for (c = 0; c < newNumIndices; c++) {
5076:                 for (k = 0; k < dof; k++) {
5077:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5078:                 }
5079:               }
5080:             }
5081:           }
5082:           else {
5083:             /* copy this row as is */
5084:             for (r = 0; r < dof; r++) {
5085:               for (c = 0; c < newNumIndices; c++) {
5086:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5087:               }
5088:             }
5089:           }
5090:           oldOff += dof;
5091:         }
5092:       }

5094:       DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5095:     }
5096:     else {
5097:       newValues = tmpValues;
5098:     }
5099:   }

5101:   /* clean up */
5102:   DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);
5103:   DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);

5105:   if (numFields) {
5106:     for (f = 0; f < numFields; f++) {
5107:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
5108:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
5109:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
5110:     }
5111:   }
5112:   else {
5113:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
5114:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
5115:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);
5116:   }
5117:   ISRestoreIndices(aIS,&anchors);

5119:   /* output */
5120:   if (outPoints) {
5121:     *outPoints = newPoints;
5122:   }
5123:   else {
5124:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5125:   }
5126:   if (outValues) {
5127:     *outValues = newValues;
5128:   }
5129:   for (f = 0; f <= numFields; f++) {
5130:     offsets[f] = newOffsets[f];
5131:   }
5132:   return(0);
5133: }

5137: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5138: {
5139:   PetscSection    clSection;
5140:   IS              clPoints;
5141:   const PetscInt *clp;
5142:   const PetscInt  **perms[32] = {NULL};
5143:   PetscInt       *points = NULL, *pointsNew;
5144:   PetscInt        numPoints, numPointsNew;
5145:   PetscInt        offsets[32];
5146:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5147:   PetscErrorCode  ierr;

5155:   PetscSectionGetNumFields(section, &Nf);
5156:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5157:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5158:   /* Get points in closure */
5159:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5160:   /* Get number of indices and indices per field */
5161:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5162:     PetscInt dof, fdof;

5164:     PetscSectionGetDof(section, points[p], &dof);
5165:     for (f = 0; f < Nf; ++f) {
5166:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5167:       offsets[f+1] += fdof;
5168:     }
5169:     Nind += dof;
5170:   }
5171:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5172:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5173:   if (!Nf) offsets[1] = Nind;
5174:   /* Get dual space symmetries */
5175:   for (f = 0; f < PetscMax(1,Nf); f++) {
5176:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5177:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5178:   }
5179:   /* Correct for hanging node constraints */
5180:   {
5181:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5182:     if (numPointsNew) {
5183:       for (f = 0; f < PetscMax(1,Nf); f++) {
5184:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5185:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5186:       }
5187:       for (f = 0; f < PetscMax(1,Nf); f++) {
5188:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5189:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5190:       }
5191:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5192:       numPoints = numPointsNew;
5193:       Nind      = NindNew;
5194:       points    = pointsNew;
5195:     }
5196:   }
5197:   /* Calculate indices */
5198:   DMGetWorkArray(dm, Nind, PETSC_INT, indices);
5199:   if (Nf) {
5200:     if (outOffsets) {
5201:       PetscInt f;

5203:       for (f = 0; f <= Nf; f++) {
5204:         outOffsets[f] = offsets[f];
5205:       }
5206:     }
5207:     for (p = 0; p < numPoints; p++) {
5208:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5209:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5210:     }
5211:   } else {
5212:     for (p = 0, off = 0; p < numPoints; p++) {
5213:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5215:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5216:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5217:     }
5218:   }
5219:   /* Cleanup points */
5220:   for (f = 0; f < PetscMax(1,Nf); f++) {
5221:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5222:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5223:   }
5224:   if (numPointsNew) {
5225:     DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);
5226:   } else {
5227:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5228:   }
5229:   if (numIndices) *numIndices = Nind;
5230:   return(0);
5231: }

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

5242:   DMRestoreWorkArray(dm, 0, PETSC_INT, indices);
5243:   return(0);
5244: }

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

5251:   Not collective

5253:   Input Parameters:
5254: + dm - The DM
5255: . section - The section describing the layout in v, or NULL to use the default section
5256: . globalSection - The section describing the layout in v, or NULL to use the default global section
5257: . A - The matrix
5258: . point - The sieve point in the DM
5259: . values - The array of values
5260: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5265:   Level: intermediate

5267: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5268: @*/
5269: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5270: {
5271:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5272:   PetscSection        clSection;
5273:   IS                  clPoints;
5274:   PetscInt           *points = NULL, *newPoints;
5275:   const PetscInt     *clp;
5276:   PetscInt           *indices;
5277:   PetscInt            offsets[32];
5278:   const PetscInt    **perms[32] = {NULL};
5279:   const PetscScalar **flips[32] = {NULL};
5280:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5281:   PetscScalar        *valCopy = NULL;
5282:   PetscScalar        *newValues;
5283:   PetscErrorCode      ierr;

5287:   if (!section) {DMGetDefaultSection(dm, &section);}
5289:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5292:   PetscSectionGetNumFields(section, &numFields);
5293:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5294:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5295:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5296:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5297:     PetscInt fdof;

5299:     PetscSectionGetDof(section, points[p], &dof);
5300:     for (f = 0; f < numFields; ++f) {
5301:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5302:       offsets[f+1] += fdof;
5303:     }
5304:     numIndices += dof;
5305:   }
5306:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

5308:   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5309:   /* Get symmetries */
5310:   for (f = 0; f < PetscMax(1,numFields); f++) {
5311:     if (numFields) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5312:     else           {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5313:     if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5314:       PetscInt foffset = offsets[f];

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

5320:         if (!numFields) {
5321:           PetscSectionGetDof(section,point,&fdof);
5322:         } else {
5323:           PetscSectionGetFieldDof(section,point,f,&fdof);
5324:         }
5325:         if (flip) {
5326:           PetscInt i, j, k;

5328:           if (!valCopy) {
5329:             DMGetWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5330:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5331:             values = valCopy;
5332:           }
5333:           for (i = 0; i < fdof; i++) {
5334:             PetscScalar fval = flip[i];

5336:             for (k = 0; k < numIndices; k++) {
5337:               valCopy[numIndices * (foffset + i) + k] *= fval;
5338:               valCopy[numIndices * k + (foffset + i)] *= fval;
5339:             }
5340:           }
5341:         }
5342:         foffset += fdof;
5343:       }
5344:     }
5345:   }
5346:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5347:   if (newNumPoints) {
5348:     if (valCopy) {
5349:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5350:     }
5351:     for (f = 0; f < PetscMax(1,numFields); f++) {
5352:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5353:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5354:     }
5355:     for (f = 0; f < PetscMax(1,numFields); f++) {
5356:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5357:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5358:     }
5359:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5360:     numPoints  = newNumPoints;
5361:     numIndices = newNumIndices;
5362:     points     = newPoints;
5363:     values     = newValues;
5364:   }
5365:   DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
5366:   if (numFields) {
5367:     for (p = 0; p < numPoints; p++) {
5368:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5369:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5370:     }
5371:   } else {
5372:     for (p = 0, off = 0; p < numPoints; p++) {
5373:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5374:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5375:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5376:     }
5377:   }
5378:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5379:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5380:   if (mesh->printFEM > 1) {
5381:     PetscInt i;
5382:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5383:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5384:     PetscPrintf(PETSC_COMM_SELF, "\n");
5385:   }
5386:   if (ierr) {
5387:     PetscMPIInt    rank;
5388:     PetscErrorCode ierr2;

5390:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5391:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5392:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5393:     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5394: 
5395:   }
5396:   for (f = 0; f < PetscMax(1,numFields); f++) {
5397:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5398:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5399:   }
5400:   if (newNumPoints) {
5401:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5402:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5403:   }
5404:   else {
5405:     if (valCopy) {
5406:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5407:     }
5408:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5409:   }
5410:   DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
5411:   return(0);
5412: }

5416: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5417: {
5418:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5419:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5420:   PetscInt       *cpoints = NULL;
5421:   PetscInt       *findices, *cindices;
5422:   PetscInt        foffsets[32], coffsets[32];
5423:   CellRefiner     cellRefiner;
5424:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5425:   PetscErrorCode  ierr;

5430:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5432:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5434:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5436:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5439:   PetscSectionGetNumFields(fsection, &numFields);
5440:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5441:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5442:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5443:   /* Column indices */
5444:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5445:   maxFPoints = numCPoints;
5446:   /* Compress out points not in the section */
5447:   /*   TODO: Squeeze out points with 0 dof as well */
5448:   PetscSectionGetChart(csection, &pStart, &pEnd);
5449:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5450:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5451:       cpoints[q*2]   = cpoints[p];
5452:       cpoints[q*2+1] = cpoints[p+1];
5453:       ++q;
5454:     }
5455:   }
5456:   numCPoints = q;
5457:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5458:     PetscInt fdof;

5460:     PetscSectionGetDof(csection, cpoints[p], &dof);
5461:     if (!dof) continue;
5462:     for (f = 0; f < numFields; ++f) {
5463:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5464:       coffsets[f+1] += fdof;
5465:     }
5466:     numCIndices += dof;
5467:   }
5468:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5469:   /* Row indices */
5470:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5471:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5472:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5473:   for (r = 0, q = 0; r < numSubcells; ++r) {
5474:     /* TODO Map from coarse to fine cells */
5475:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5476:     /* Compress out points not in the section */
5477:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5478:     for (p = 0; p < numFPoints*2; p += 2) {
5479:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5480:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5481:         if (!dof) continue;
5482:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5483:         if (s < q) continue;
5484:         ftotpoints[q*2]   = fpoints[p];
5485:         ftotpoints[q*2+1] = fpoints[p+1];
5486:         ++q;
5487:       }
5488:     }
5489:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5490:   }
5491:   numFPoints = q;
5492:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5493:     PetscInt fdof;

5495:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5496:     if (!dof) continue;
5497:     for (f = 0; f < numFields; ++f) {
5498:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5499:       foffsets[f+1] += fdof;
5500:     }
5501:     numFIndices += dof;
5502:   }
5503:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5505:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5506:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5507:   DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5508:   DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5509:   if (numFields) {
5510:     const PetscInt **permsF[32] = {NULL};
5511:     const PetscInt **permsC[32] = {NULL};

5513:     for (f = 0; f < numFields; f++) {
5514:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5515:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5516:     }
5517:     for (p = 0; p < numFPoints; p++) {
5518:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5519:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5520:     }
5521:     for (p = 0; p < numCPoints; p++) {
5522:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5523:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5524:     }
5525:     for (f = 0; f < numFields; f++) {
5526:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5527:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5528:     }
5529:   } else {
5530:     const PetscInt **permsF = NULL;
5531:     const PetscInt **permsC = NULL;

5533:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5534:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5535:     for (p = 0, off = 0; p < numFPoints; p++) {
5536:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5538:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5539:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5540:     }
5541:     for (p = 0, off = 0; p < numCPoints; p++) {
5542:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5544:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5545:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5546:     }
5547:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5548:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5549:   }
5550:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5551:   /* TODO: flips */
5552:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5553:   if (ierr) {
5554:     PetscMPIInt    rank;
5555:     PetscErrorCode ierr2;

5557:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5558:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5559:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5560:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5561:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5562: 
5563:   }
5564:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5565:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5566:   DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5567:   DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5568:   return(0);
5569: }

5573: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5574: {
5575:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5576:   PetscInt      *cpoints = NULL;
5577:   PetscInt       foffsets[32], coffsets[32];
5578:   CellRefiner    cellRefiner;
5579:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

5585:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5587:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5589:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5591:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5593:   PetscSectionGetNumFields(fsection, &numFields);
5594:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5595:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5596:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5597:   /* Column indices */
5598:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5599:   maxFPoints = numCPoints;
5600:   /* Compress out points not in the section */
5601:   /*   TODO: Squeeze out points with 0 dof as well */
5602:   PetscSectionGetChart(csection, &pStart, &pEnd);
5603:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5604:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5605:       cpoints[q*2]   = cpoints[p];
5606:       cpoints[q*2+1] = cpoints[p+1];
5607:       ++q;
5608:     }
5609:   }
5610:   numCPoints = q;
5611:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5612:     PetscInt fdof;

5614:     PetscSectionGetDof(csection, cpoints[p], &dof);
5615:     if (!dof) continue;
5616:     for (f = 0; f < numFields; ++f) {
5617:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5618:       coffsets[f+1] += fdof;
5619:     }
5620:     numCIndices += dof;
5621:   }
5622:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5623:   /* Row indices */
5624:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5625:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5626:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5627:   for (r = 0, q = 0; r < numSubcells; ++r) {
5628:     /* TODO Map from coarse to fine cells */
5629:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5630:     /* Compress out points not in the section */
5631:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5632:     for (p = 0; p < numFPoints*2; p += 2) {
5633:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5634:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5635:         if (!dof) continue;
5636:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5637:         if (s < q) continue;
5638:         ftotpoints[q*2]   = fpoints[p];
5639:         ftotpoints[q*2+1] = fpoints[p+1];
5640:         ++q;
5641:       }
5642:     }
5643:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5644:   }
5645:   numFPoints = q;
5646:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5647:     PetscInt fdof;

5649:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5650:     if (!dof) continue;
5651:     for (f = 0; f < numFields; ++f) {
5652:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5653:       foffsets[f+1] += fdof;
5654:     }
5655:     numFIndices += dof;
5656:   }
5657:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5659:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5660:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5661:   if (numFields) {
5662:     const PetscInt **permsF[32] = {NULL};
5663:     const PetscInt **permsC[32] = {NULL};

5665:     for (f = 0; f < numFields; f++) {
5666:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5667:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5668:     }
5669:     for (p = 0; p < numFPoints; p++) {
5670:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5671:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5672:     }
5673:     for (p = 0; p < numCPoints; p++) {
5674:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5675:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5676:     }
5677:     for (f = 0; f < numFields; f++) {
5678:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5679:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5680:     }
5681:   } else {
5682:     const PetscInt **permsF = NULL;
5683:     const PetscInt **permsC = NULL;

5685:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5686:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5687:     for (p = 0, off = 0; p < numFPoints; p++) {
5688:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5690:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5691:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5692:     }
5693:     for (p = 0, off = 0; p < numCPoints; p++) {
5694:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5696:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5697:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5698:     }
5699:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5700:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5701:   }
5702:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5703:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5704:   return(0);
5705: }

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

5712:   Input Parameter:
5713: . dm - The DMPlex object

5715:   Output Parameters:
5716: + cMax - The first hybrid cell
5717: . fMax - The first hybrid face
5718: . eMax - The first hybrid edge
5719: - vMax - The first hybrid vertex

5721:   Level: developer

5723: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5724: @*/
5725: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5726: {
5727:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5728:   PetscInt       dim;

5733:   DMGetDimension(dm, &dim);
5734:   if (cMax) *cMax = mesh->hybridPointMax[dim];
5735:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5736:   if (eMax) *eMax = mesh->hybridPointMax[1];
5737:   if (vMax) *vMax = mesh->hybridPointMax[0];
5738:   return(0);
5739: }

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

5746:   Input Parameters:
5747: . dm   - The DMPlex object
5748: . cMax - The first hybrid cell
5749: . fMax - The first hybrid face
5750: . eMax - The first hybrid edge
5751: - vMax - The first hybrid vertex

5753:   Level: developer

5755: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5756: @*/
5757: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5758: {
5759:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5760:   PetscInt       dim;

5765:   DMGetDimension(dm, &dim);
5766:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5767:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5768:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5769:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5770:   return(0);
5771: }

5775: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5776: {
5777:   DM_Plex *mesh = (DM_Plex*) dm->data;

5782:   *cellHeight = mesh->vtkCellHeight;
5783:   return(0);
5784: }

5788: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5789: {
5790:   DM_Plex *mesh = (DM_Plex*) dm->data;

5794:   mesh->vtkCellHeight = cellHeight;
5795:   return(0);
5796: }

5800: /* We can easily have a form that takes an IS instead */
5801: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5802: {
5803:   PetscSection   section, globalSection;
5804:   PetscInt      *numbers, p;

5808:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
5809:   PetscSectionSetChart(section, pStart, pEnd);
5810:   for (p = pStart; p < pEnd; ++p) {
5811:     PetscSectionSetDof(section, p, 1);
5812:   }
5813:   PetscSectionSetUp(section);
5814:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
5815:   PetscMalloc1(pEnd - pStart, &numbers);
5816:   for (p = pStart; p < pEnd; ++p) {
5817:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
5818:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5819:     else                       numbers[p-pStart] += shift;
5820:   }
5821:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
5822:   if (globalSize) {
5823:     PetscLayout layout;
5824:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
5825:     PetscLayoutGetSize(layout, globalSize);
5826:     PetscLayoutDestroy(&layout);
5827:   }
5828:   PetscSectionDestroy(&section);
5829:   PetscSectionDestroy(&globalSection);
5830:   return(0);
5831: }

5835: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5836: {
5837:   PetscInt       cellHeight, cStart, cEnd, cMax;

5841:   DMPlexGetVTKCellHeight(dm, &cellHeight);
5842:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5843:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5844:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5845:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
5846:   return(0);
5847: }

5851: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5852: {
5853:   DM_Plex       *mesh = (DM_Plex*) dm->data;

5858:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
5859:   *globalCellNumbers = mesh->globalCellNumbers;
5860:   return(0);
5861: }

5865: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
5866: {
5867:   PetscInt       vStart, vEnd, vMax;

5872:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5873:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
5874:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
5875:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
5876:   return(0);
5877: }

5881: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5882: {
5883:   DM_Plex       *mesh = (DM_Plex*) dm->data;

5888:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
5889:   *globalVertexNumbers = mesh->globalVertexNumbers;
5890:   return(0);
5891: }

5895: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
5896: {
5897:   IS             nums[4];
5898:   PetscInt       depths[4];
5899:   PetscInt       depth, d, shift = 0;

5904:   DMPlexGetDepth(dm, &depth);
5905:   /* For unstratified meshes use dim instead of depth */
5906:   if (depth < 0) {DMGetDimension(dm, &depth);}
5907:   depths[0] = depth; depths[1] = 0;
5908:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
5909:   for (d = 0; d <= depth; ++d) {
5910:     PetscInt pStart, pEnd, gsize;

5912:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
5913:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
5914:     shift += gsize;
5915:   }
5916:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
5917:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
5918:   return(0);
5919: }

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

5926:   Input Parameters:
5927:   + dm - The DMPlex object

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

5931:   Level: developer

5933: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
5934: @*/
5935: PetscErrorCode DMPlexCheckSymmetry(DM dm)
5936: {
5937:   PetscSection    coneSection, supportSection;
5938:   const PetscInt *cone, *support;
5939:   PetscInt        coneSize, c, supportSize, s;
5940:   PetscInt        pStart, pEnd, p, csize, ssize;
5941:   PetscErrorCode  ierr;

5945:   DMPlexGetConeSection(dm, &coneSection);
5946:   DMPlexGetSupportSection(dm, &supportSection);
5947:   /* Check that point p is found in the support of its cone points, and vice versa */
5948:   DMPlexGetChart(dm, &pStart, &pEnd);
5949:   for (p = pStart; p < pEnd; ++p) {
5950:     DMPlexGetConeSize(dm, p, &coneSize);
5951:     DMPlexGetCone(dm, p, &cone);
5952:     for (c = 0; c < coneSize; ++c) {
5953:       PetscBool dup = PETSC_FALSE;
5954:       PetscInt  d;
5955:       for (d = c-1; d >= 0; --d) {
5956:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
5957:       }
5958:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
5959:       DMPlexGetSupport(dm, cone[c], &support);
5960:       for (s = 0; s < supportSize; ++s) {
5961:         if (support[s] == p) break;
5962:       }
5963:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
5964:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
5965:         for (s = 0; s < coneSize; ++s) {
5966:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
5967:         }
5968:         PetscPrintf(PETSC_COMM_SELF, "\n");
5969:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
5970:         for (s = 0; s < supportSize; ++s) {
5971:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
5972:         }
5973:         PetscPrintf(PETSC_COMM_SELF, "\n");
5974:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
5975:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
5976:       }
5977:     }
5978:     DMPlexGetSupportSize(dm, p, &supportSize);
5979:     DMPlexGetSupport(dm, p, &support);
5980:     for (s = 0; s < supportSize; ++s) {
5981:       DMPlexGetConeSize(dm, support[s], &coneSize);
5982:       DMPlexGetCone(dm, support[s], &cone);
5983:       for (c = 0; c < coneSize; ++c) {
5984:         if (cone[c] == p) break;
5985:       }
5986:       if (c >= coneSize) {
5987:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
5988:         for (c = 0; c < supportSize; ++c) {
5989:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
5990:         }
5991:         PetscPrintf(PETSC_COMM_SELF, "\n");
5992:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
5993:         for (c = 0; c < coneSize; ++c) {
5994:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
5995:         }
5996:         PetscPrintf(PETSC_COMM_SELF, "\n");
5997:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
5998:       }
5999:     }
6000:   }
6001:   PetscSectionGetStorageSize(coneSection, &csize);
6002:   PetscSectionGetStorageSize(supportSection, &ssize);
6003:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6004:   return(0);
6005: }

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

6012:   Input Parameters:
6013: + dm - The DMPlex object
6014: . isSimplex - Are the cells simplices or tensor products
6015: - cellHeight - Normally 0

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

6019:   Level: developer

6021: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6022: @*/
6023: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6024: {
6025:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6030:   DMGetDimension(dm, &dim);
6031:   switch (dim) {
6032:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6033:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6034:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6035:   default:
6036:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6037:   }
6038:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6039:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6040:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6041:   cMax = cMax >= 0 ? cMax : cEnd;
6042:   for (c = cStart; c < cMax; ++c) {
6043:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6045:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6046:     for (cl = 0; cl < closureSize*2; cl += 2) {
6047:       const PetscInt p = closure[cl];
6048:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6049:     }
6050:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6051:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6052:   }
6053:   for (c = cMax; c < cEnd; ++c) {
6054:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6056:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6057:     for (cl = 0; cl < closureSize*2; cl += 2) {
6058:       const PetscInt p = closure[cl];
6059:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6060:     }
6061:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6062:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6063:   }
6064:   return(0);
6065: }

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

6072:   Input Parameters:
6073: + dm - The DMPlex object
6074: . isSimplex - Are the cells simplices or tensor products
6075: - cellHeight - Normally 0

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

6079:   Level: developer

6081: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6082: @*/
6083: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6084: {
6085:   PetscInt       pMax[4];
6086:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

6091:   DMGetDimension(dm, &dim);
6092:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6093:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6094:   for (h = cellHeight; h < dim; ++h) {
6095:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6096:     for (c = cStart; c < cEnd; ++c) {
6097:       const PetscInt *cone, *ornt, *faces;
6098:       PetscInt        numFaces, faceSize, coneSize,f;
6099:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6101:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6102:       DMPlexGetConeSize(dm, c, &coneSize);
6103:       DMPlexGetCone(dm, c, &cone);
6104:       DMPlexGetConeOrientation(dm, c, &ornt);
6105:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6106:       for (cl = 0; cl < closureSize*2; cl += 2) {
6107:         const PetscInt p = closure[cl];
6108:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6109:       }
6110:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6111:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6112:       for (f = 0; f < numFaces; ++f) {
6113:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6115:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6116:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6117:           const PetscInt p = fclosure[cl];
6118:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6119:         }
6120:         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);
6121:         for (v = 0; v < fnumCorners; ++v) {
6122:           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]);
6123:         }
6124:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6125:       }
6126:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6127:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6128:     }
6129:   }
6130:   return(0);
6131: }

6135: /* Pointwise interpolation
6136:      Just code FEM for now
6137:      u^f = I u^c
6138:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6139:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6140:      I_{ij} = psi^f_i phi^c_j
6141: */
6142: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6143: {
6144:   PetscSection   gsc, gsf;
6145:   PetscInt       m, n;
6146:   void          *ctx;
6147:   DM             cdm;
6148:   PetscBool      regular;

6152:   DMGetDefaultGlobalSection(dmFine, &gsf);
6153:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6154:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6155:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6157:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6158:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6159:   MatSetType(*interpolation, dmCoarse->mattype);
6160:   DMGetApplicationContext(dmFine, &ctx);

6162:   DMGetCoarseDM(dmFine, &cdm);
6163:   DMPlexGetRegularRefinement(dmFine, &regular);
6164:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6165:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6166:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6167:   /* Use naive scaling */
6168:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6169:   return(0);
6170: }

6174: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6175: {
6177:   VecScatter     ctx;

6180:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6181:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6182:   VecScatterDestroy(&ctx);
6183:   return(0);
6184: }

6188: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6189: {
6190:   PetscSection   section;
6191:   IS            *bcPoints, *bcComps;
6192:   PetscBool     *isFE;
6193:   PetscInt      *bcFields, *numComp, *numDof;
6194:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6195:   PetscInt       cStart, cEnd, cEndInterior;

6199:   DMGetNumFields(dm, &numFields);
6200:   if (!numFields) return(0);
6201:   /* FE and FV boundary conditions are handled slightly differently */
6202:   PetscMalloc1(numFields, &isFE);
6203:   for (f = 0; f < numFields; ++f) {
6204:     PetscObject  obj;
6205:     PetscClassId id;

6207:     DMGetField(dm, f, &obj);
6208:     PetscObjectGetClassId(obj, &id);
6209:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6210:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6211:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6212:   }
6213:   /* Allocate boundary point storage for FEM boundaries */
6214:   DMPlexGetDepth(dm, &depth);
6215:   DMGetDimension(dm, &dim);
6216:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6217:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6218:   PetscDSGetNumBoundary(dm->prob, &numBd);
6219:   for (bd = 0; bd < numBd; ++bd) {
6220:     PetscInt    field;
6221:     PetscBool   isEssential;
6222:     const char  *labelName;
6223:     DMLabel     label;

6225:     PetscDSGetBoundary(dm->prob, bd, &isEssential, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6226:     DMGetLabel(dm,labelName,&label);
6227:     if (label && isFE[field] && isEssential) ++numBC;
6228:   }
6229:   /* Add ghost cell boundaries for FVM */
6230:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6231:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6232:   /* Constrain ghost cells for FV */
6233:   for (f = 0; f < numFields; ++f) {
6234:     PetscInt *newidx, c;

6236:     if (isFE[f] || cEndInterior < 0) continue;
6237:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6238:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6239:     bcFields[bc] = f;
6240:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6241:   }
6242:   /* Handle FEM Dirichlet boundaries */
6243:   for (bd = 0; bd < numBd; ++bd) {
6244:     const char     *bdLabel;
6245:     DMLabel         label;
6246:     const PetscInt *comps;
6247:     const PetscInt *values;
6248:     PetscInt        bd2, field, numComps, numValues;
6249:     PetscBool       isEssential, duplicate = PETSC_FALSE;

6251:     PetscDSGetBoundary(dm->prob, bd, &isEssential, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6252:     DMGetLabel(dm, bdLabel, &label);
6253:     if (!isFE[field] || !label) continue;
6254:     /* Only want to modify label once */
6255:     for (bd2 = 0; bd2 < bd; ++bd2) {
6256:       const char *bdname;
6257:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6258:       PetscStrcmp(bdname, bdLabel, &duplicate);
6259:       if (duplicate) break;
6260:     }
6261:     if (!duplicate && (isFE[field])) {
6262:       /* don't complete cells, which are just present to give orientation to the boundary */
6263:       DMPlexLabelComplete(dm, label);
6264:     }
6265:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6266:     if (isEssential) {
6267:       PetscInt       *newidx;
6268:       PetscInt        n, newn = 0, p, v;

6270:       bcFields[bc] = field;
6271:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6272:       for (v = 0; v < numValues; ++v) {
6273:         IS              tmp;
6274:         const PetscInt *idx;

6276:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6277:         if (!tmp) continue;
6278:         ISGetLocalSize(tmp, &n);
6279:         ISGetIndices(tmp, &idx);
6280:         if (isFE[field]) {
6281:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6282:         } else {
6283:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6284:         }
6285:         ISRestoreIndices(tmp, &idx);
6286:         ISDestroy(&tmp);
6287:       }
6288:       PetscMalloc1(newn,&newidx);
6289:       newn = 0;
6290:       for (v = 0; v < numValues; ++v) {
6291:         IS              tmp;
6292:         const PetscInt *idx;

6294:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6295:         if (!tmp) continue;
6296:         ISGetLocalSize(tmp, &n);
6297:         ISGetIndices(tmp, &idx);
6298:         if (isFE[field]) {
6299:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6300:         } else {
6301:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6302:         }
6303:         ISRestoreIndices(tmp, &idx);
6304:         ISDestroy(&tmp);
6305:       }
6306:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6307:     }
6308:   }
6309:   /* Handle discretization */
6310:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6311:   for (f = 0; f < numFields; ++f) {
6312:     PetscObject obj;

6314:     DMGetField(dm, f, &obj);
6315:     if (isFE[f]) {
6316:       PetscFE         fe = (PetscFE) obj;
6317:       const PetscInt *numFieldDof;
6318:       PetscInt        d;

6320:       PetscFEGetNumComponents(fe, &numComp[f]);
6321:       PetscFEGetNumDof(fe, &numFieldDof);
6322:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6323:     } else {
6324:       PetscFV fv = (PetscFV) obj;

6326:       PetscFVGetNumComponents(fv, &numComp[f]);
6327:       numDof[f*(dim+1)+dim] = numComp[f];
6328:     }
6329:   }
6330:   for (f = 0; f < numFields; ++f) {
6331:     PetscInt d;
6332:     for (d = 1; d < dim; ++d) {
6333:       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.");
6334:     }
6335:   }
6336:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6337:   for (f = 0; f < numFields; ++f) {
6338:     PetscFE     fe;
6339:     const char *name;

6341:     DMGetField(dm, f, (PetscObject *) &fe);
6342:     PetscObjectGetName((PetscObject) fe, &name);
6343:     PetscSectionSetFieldName(section, f, name);
6344:   }
6345:   DMSetDefaultSection(dm, section);
6346:   PetscSectionDestroy(&section);
6347:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6348:   PetscFree3(bcFields,bcPoints,bcComps);
6349:   PetscFree2(numComp,numDof);
6350:   PetscFree(isFE);
6351:   return(0);
6352: }

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

6359:   Input Parameter:
6360: . dm - The DMPlex object

6362:   Output Parameter:
6363: . regular - The flag

6365:   Level: intermediate

6367: .seealso: DMPlexSetRegularRefinement()
6368: @*/
6369: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6370: {
6374:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6375:   return(0);
6376: }

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

6383:   Input Parameters:
6384: + dm - The DMPlex object
6385: - regular - The flag

6387:   Level: intermediate

6389: .seealso: DMPlexGetRegularRefinement()
6390: @*/
6391: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6392: {
6395:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6396:   return(0);
6397: }

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

6406:   not collective

6408:   Input Parameters:
6409: . dm - The DMPlex object

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


6416:   Level: intermediate

6418: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6419: @*/
6420: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6421: {
6422:   DM_Plex *plex = (DM_Plex *)dm->data;

6427:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6428:   if (anchorSection) *anchorSection = plex->anchorSection;
6429:   if (anchorIS) *anchorIS = plex->anchorIS;
6430:   return(0);
6431: }

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

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

6443:   collective on dm

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

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

6452:   Level: intermediate

6454: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6455: @*/
6456: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6457: {
6458:   DM_Plex        *plex = (DM_Plex *)dm->data;
6459:   PetscMPIInt    result;

6464:   if (anchorSection) {
6466:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6467:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6468:   }
6469:   if (anchorIS) {
6471:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6472:     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6473:   }

6475:   PetscObjectReference((PetscObject)anchorSection);
6476:   PetscSectionDestroy(&plex->anchorSection);
6477:   plex->anchorSection = anchorSection;

6479:   PetscObjectReference((PetscObject)anchorIS);
6480:   ISDestroy(&plex->anchorIS);
6481:   plex->anchorIS = anchorIS;

6483: #if defined(PETSC_USE_DEBUG)
6484:   if (anchorIS && anchorSection) {
6485:     PetscInt size, a, pStart, pEnd;
6486:     const PetscInt *anchors;

6488:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6489:     ISGetLocalSize(anchorIS,&size);
6490:     ISGetIndices(anchorIS,&anchors);
6491:     for (a = 0; a < size; a++) {
6492:       PetscInt p;

6494:       p = anchors[a];
6495:       if (p >= pStart && p < pEnd) {
6496:         PetscInt dof;

6498:         PetscSectionGetDof(anchorSection,p,&dof);
6499:         if (dof) {
6500:           PetscErrorCode ierr2;

6502:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6503:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6504:         }
6505:       }
6506:     }
6507:     ISRestoreIndices(anchorIS,&anchors);
6508:   }
6509: #endif
6510:   /* reset the generic constraints */
6511:   DMSetDefaultConstraints(dm,NULL,NULL);
6512:   return(0);
6513: }

6517: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6518: {
6519:   PetscSection anchorSection;
6520:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

6525:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6526:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6527:   PetscSectionGetNumFields(section,&numFields);
6528:   if (numFields) {
6529:     PetscInt f;
6530:     PetscSectionSetNumFields(*cSec,numFields);

6532:     for (f = 0; f < numFields; f++) {
6533:       PetscInt numComp;

6535:       PetscSectionGetFieldComponents(section,f,&numComp);
6536:       PetscSectionSetFieldComponents(*cSec,f,numComp);
6537:     }
6538:   }
6539:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6540:   PetscSectionGetChart(section,&sStart,&sEnd);
6541:   pStart = PetscMax(pStart,sStart);
6542:   pEnd   = PetscMin(pEnd,sEnd);
6543:   pEnd   = PetscMax(pStart,pEnd);
6544:   PetscSectionSetChart(*cSec,pStart,pEnd);
6545:   for (p = pStart; p < pEnd; p++) {
6546:     PetscSectionGetDof(anchorSection,p,&dof);
6547:     if (dof) {
6548:       PetscSectionGetDof(section,p,&dof);
6549:       PetscSectionSetDof(*cSec,p,dof);
6550:       for (f = 0; f < numFields; f++) {
6551:         PetscSectionGetFieldDof(section,p,f,&dof);
6552:         PetscSectionSetFieldDof(*cSec,p,f,dof);
6553:       }
6554:     }
6555:   }
6556:   PetscSectionSetUp(*cSec);
6557:   return(0);
6558: }

6562: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6563: {
6564:   PetscSection aSec;
6565:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6566:   const PetscInt *anchors;
6567:   PetscInt numFields, f;
6568:   IS aIS;

6573:   PetscSectionGetStorageSize(cSec, &m);
6574:   PetscSectionGetStorageSize(section, &n);
6575:   MatCreate(PETSC_COMM_SELF,cMat);
6576:   MatSetSizes(*cMat,m,n,m,n);
6577:   MatSetType(*cMat,MATSEQAIJ);
6578:   DMPlexGetAnchors(dm,&aSec,&aIS);
6579:   ISGetIndices(aIS,&anchors);
6580:   /* cSec will be a subset of aSec and section */
6581:   PetscSectionGetChart(cSec,&pStart,&pEnd);
6582:   PetscMalloc1(m+1,&i);
6583:   i[0] = 0;
6584:   PetscSectionGetNumFields(section,&numFields);
6585:   for (p = pStart; p < pEnd; p++) {
6586:     PetscInt rDof, rOff, r;

6588:     PetscSectionGetDof(aSec,p,&rDof);
6589:     if (!rDof) continue;
6590:     PetscSectionGetOffset(aSec,p,&rOff);
6591:     if (numFields) {
6592:       for (f = 0; f < numFields; f++) {
6593:         annz = 0;
6594:         for (r = 0; r < rDof; r++) {
6595:           a = anchors[rOff + r];
6596:           PetscSectionGetFieldDof(section,a,f,&aDof);
6597:           annz += aDof;
6598:         }
6599:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6600:         PetscSectionGetFieldOffset(cSec,p,f,&off);
6601:         for (q = 0; q < dof; q++) {
6602:           i[off + q + 1] = i[off + q] + annz;
6603:         }
6604:       }
6605:     }
6606:     else {
6607:       annz = 0;
6608:       for (q = 0; q < dof; q++) {
6609:         a = anchors[off + q];
6610:         PetscSectionGetDof(section,a,&aDof);
6611:         annz += aDof;
6612:       }
6613:       PetscSectionGetDof(cSec,p,&dof);
6614:       PetscSectionGetOffset(cSec,p,&off);
6615:       for (q = 0; q < dof; q++) {
6616:         i[off + q + 1] = i[off + q] + annz;
6617:       }
6618:     }
6619:   }
6620:   nnz = i[m];
6621:   PetscMalloc1(nnz,&j);
6622:   offset = 0;
6623:   for (p = pStart; p < pEnd; p++) {
6624:     if (numFields) {
6625:       for (f = 0; f < numFields; f++) {
6626:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6627:         for (q = 0; q < dof; q++) {
6628:           PetscInt rDof, rOff, r;
6629:           PetscSectionGetDof(aSec,p,&rDof);
6630:           PetscSectionGetOffset(aSec,p,&rOff);
6631:           for (r = 0; r < rDof; r++) {
6632:             PetscInt s;

6634:             a = anchors[rOff + r];
6635:             PetscSectionGetFieldDof(section,a,f,&aDof);
6636:             PetscSectionGetFieldOffset(section,a,f,&aOff);
6637:             for (s = 0; s < aDof; s++) {
6638:               j[offset++] = aOff + s;
6639:             }
6640:           }
6641:         }
6642:       }
6643:     }
6644:     else {
6645:       PetscSectionGetDof(cSec,p,&dof);
6646:       for (q = 0; q < dof; q++) {
6647:         PetscInt rDof, rOff, r;
6648:         PetscSectionGetDof(aSec,p,&rDof);
6649:         PetscSectionGetOffset(aSec,p,&rOff);
6650:         for (r = 0; r < rDof; r++) {
6651:           PetscInt s;

6653:           a = anchors[rOff + r];
6654:           PetscSectionGetDof(section,a,&aDof);
6655:           PetscSectionGetOffset(section,a,&aOff);
6656:           for (s = 0; s < aDof; s++) {
6657:             j[offset++] = aOff + s;
6658:           }
6659:         }
6660:       }
6661:     }
6662:   }
6663:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
6664:   PetscFree(i);
6665:   PetscFree(j);
6666:   ISRestoreIndices(aIS,&anchors);
6667:   return(0);
6668: }

6672: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6673: {
6674:   DM_Plex        *plex = (DM_Plex *)dm->data;
6675:   PetscSection   anchorSection, section, cSec;
6676:   Mat            cMat;

6681:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6682:   if (anchorSection) {
6683:     PetscDS  ds;
6684:     PetscInt nf;

6686:     DMGetDefaultSection(dm,&section);
6687:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
6688:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
6689:     DMGetDS(dm,&ds);
6690:     PetscDSGetNumFields(ds,&nf);
6691:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
6692:     DMSetDefaultConstraints(dm,cSec,cMat);
6693:     PetscSectionDestroy(&cSec);
6694:     MatDestroy(&cMat);
6695:   }
6696:   return(0);
6697: }