Actual source code: plex.c

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

  8: /* Logging support */
  9: PetscLogEvent DMPLEX_Interpolate, PETSCPARTITIONER_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;

 11: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

 13: /*@
 14:   DMPlexRefineSimplexToTensor - Uniformly refines simplicial cells into tensor product cells.
 15:   3 quadrilaterals per triangle in 2D and 4 hexahedra per tetrahedron in 3D.

 17:   Collective

 19:   Input Parameters:
 20: . dm - The DMPlex object

 22:   Output Parameters:
 23: . dmRefined - The refined DMPlex object

 25:   Note: Returns NULL if the mesh is already a tensor product mesh.

 27:   Level: intermediate

 29: .seealso: DMPlexCreate(), DMPlexSetRefinementUniform()
 30: @*/
 31: PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined)
 32: {
 33:   PetscInt         dim, cMax, fMax, cStart, cEnd, coneSize;
 34:   CellRefiner      cellRefiner;
 35:   PetscBool        lop, allnoop, localized;
 36:   PetscErrorCode   ierr;

 40:   DMGetDimension(dm, &dim);
 41:   DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);
 42:   if (cMax >= 0 || fMax >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle hybrid meshes yet");
 43:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
 44:   if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP;
 45:   else {
 46:     DMPlexGetConeSize(dm,cStart,&coneSize);
 47:     switch (dim) {
 48:     case 1:
 49:       cellRefiner = REFINER_NOOP;
 50:     break;
 51:     case 2:
 52:       switch (coneSize) {
 53:       case 3:
 54:         cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
 55:       break;
 56:       case 4:
 57:         cellRefiner = REFINER_NOOP;
 58:       break;
 59:       default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
 60:       }
 61:     break;
 62:     case 3:
 63:       switch (coneSize) {
 64:       case 4:
 65:         cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
 66:       break;
 67:       case 6:
 68:         cellRefiner = REFINER_NOOP;
 69:       break;
 70:       default: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle coneSize %D with dimension %D",coneSize,dim);
 71:       }
 72:     break;
 73:     default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot handle dimension %D",dim);
 74:     }
 75:   }
 76:   /* return if we don't need to refine */
 77:   lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
 78:   MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
 79:   if (allnoop) {
 80:     *dmRefined = NULL;
 81:     return(0);
 82:   }
 83:   DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
 84:   DMCopyBoundary(dm, *dmRefined);
 85:   DMGetCoordinatesLocalized(dm, &localized);
 86:   if (localized) {
 87:     DMLocalizeCoordinates(*dmRefined);
 88:   }
 89:   return(0);
 90: }

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

 98:   *ft  = PETSC_VTK_POINT_FIELD;
 99:   DMGetDimension(dm, &dim);
100:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
101:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
102:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
103:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
104:   PetscSectionGetChart(section, &pStart, &pEnd);
105:   if (field >= 0) {
106:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vdof);}
107:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &cdof);}
108:   } else {
109:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vdof);}
110:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &cdof);}
111:   }
112:   if (vdof) {
113:     *sStart = vStart;
114:     *sEnd   = vEnd;
115:     if (vdof == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
116:     else             *ft = PETSC_VTK_POINT_FIELD;
117:   } else if (cdof) {
118:     *sStart = cStart;
119:     *sEnd   = cEnd;
120:     if (cdof == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
121:     else             *ft = PETSC_VTK_CELL_FIELD;
122:   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
123:   return(0);
124: }

126: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
127: {
128:   DM                 dm;
129:   PetscSection       s;
130:   PetscDraw          draw, popup;
131:   DM                 cdm;
132:   PetscSection       coordSection;
133:   Vec                coordinates;
134:   const PetscScalar *coords, *array;
135:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
136:   PetscReal          vbound[2], time;
137:   PetscBool          isnull, flg;
138:   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
139:   const char        *name;
140:   char               title[PETSC_MAX_PATH_LEN];
141:   PetscErrorCode     ierr;

144:   PetscViewerDrawGetDraw(viewer, 0, &draw);
145:   PetscDrawIsNull(draw, &isnull);
146:   if (isnull) return(0);

148:   VecGetDM(v, &dm);
149:   DMGetCoordinateDim(dm, &dim);
150:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
151:   DMGetDefaultSection(dm, &s);
152:   PetscSectionGetNumFields(s, &Nf);
153:   DMGetCoarsenLevel(dm, &level);
154:   DMGetCoordinateDM(dm, &cdm);
155:   DMGetDefaultSection(cdm, &coordSection);
156:   DMGetCoordinatesLocal(dm, &coordinates);
157:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
158:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

160:   PetscObjectGetName((PetscObject) v, &name);
161:   DMGetOutputSequenceNumber(dm, &step, &time);

163:   VecGetLocalSize(coordinates, &N);
164:   VecGetArrayRead(coordinates, &coords);
165:   for (c = 0; c < N; c += dim) {
166:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
167:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
168:   }
169:   VecRestoreArrayRead(coordinates, &coords);
170:   PetscDrawClear(draw);

172:   /* Could implement something like DMDASelectFields() */
173:   for (f = 0; f < Nf; ++f) {
174:     DM   fdm = dm;
175:     Vec  fv  = v;
176:     IS   fis;
177:     char prefix[PETSC_MAX_PATH_LEN];
178:     const char *fname;

180:     PetscSectionGetFieldComponents(s, f, &Nc);
181:     PetscSectionGetFieldName(s, f, &fname);

183:     if (v->hdr.prefix) {PetscStrcpy(prefix, v->hdr.prefix);}
184:     else               {prefix[0] = '\0';}
185:     if (Nf > 1) {
186:       DMCreateSubDM(dm, 1, &f, &fis, &fdm);
187:       VecGetSubVector(v, fis, &fv);
188:       PetscStrcat(prefix, fname);
189:       PetscStrcat(prefix, "_");
190:     }
191:     for (comp = 0; comp < Nc; ++comp, ++w) {
192:       PetscInt nmax = 2;

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

199:       /* TODO Get max and min only for this component */
200:       PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
201:       if (!flg) {
202:         VecMin(fv, NULL, &vbound[0]);
203:         VecMax(fv, NULL, &vbound[1]);
204:         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
205:       }
206:       PetscDrawGetPopup(draw, &popup);
207:       PetscDrawScalePopup(popup, vbound[0], vbound[1]);
208:       PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);

210:       VecGetArrayRead(fv, &array);
211:       for (c = cStart; c < cEnd; ++c) {
212:         PetscScalar *coords = NULL, *a = NULL;
213:         PetscInt     numCoords, color[4];

215:         DMPlexPointLocalRead(fdm, c, array, &a);
216:         if (a) {
217:           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
218:           color[1] = color[2] = color[3] = color[0];
219:         } else {
220:           PetscScalar *vals = NULL;
221:           PetscInt     numVals, va;

223:           DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
224:           if (numVals % Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %D does not divide the number of values in the closure %D", Nc, numVals);
225:           switch (numVals/Nc) {
226:           case 3: /* P1 Triangle */
227:           case 4: /* P1 Quadrangle */
228:             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
229:             break;
230:           case 6: /* P2 Triangle */
231:           case 8: /* P2 Quadrangle */
232:             for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
233:             break;
234:           default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
235:           }
236:           DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
237:         }
238:         DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
239:         switch (numCoords) {
240:         case 6:
241:           PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);
242:           break;
243:         case 8:
244:           PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);
245:           PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0]);
246:           break;
247:         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
248:         }
249:         DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
250:       }
251:       VecRestoreArrayRead(fv, &array);
252:       PetscDrawFlush(draw);
253:       PetscDrawPause(draw);
254:       PetscDrawSave(draw);
255:     }
256:     if (Nf > 1) {
257:       VecRestoreSubVector(v, fis, &fv);
258:       ISDestroy(&fis);
259:       DMDestroy(&fdm);
260:     }
261:   }
262:   return(0);
263: }

265: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
266: {
267:   DM             dm;
268:   PetscBool      isvtk, ishdf5, isdraw, isseq;

272:   VecGetDM(v, &dm);
273:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
274:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
275:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
276:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
277:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
278:   if (isvtk || ishdf5) {
279:     PetscInt  numFields;
280:     PetscBool fem = PETSC_FALSE;

282:     DMGetNumFields(dm, &numFields);
283:     if (numFields) {
284:       PetscObject fe;

286:       DMGetField(dm, 0, &fe);
287:       if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE;
288:     }
289:     if (fem) {DMPlexInsertBoundaryValues(dm, PETSC_TRUE, v, 0.0, NULL, NULL, NULL);}
290:   }
291:   if (isvtk) {
292:     PetscSection            section;
293:     PetscViewerVTKFieldType ft;
294:     PetscInt                pStart, pEnd;

296:     DMGetDefaultSection(dm, &section);
297:     DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
298:     PetscObjectReference((PetscObject) v);  /* viewer drops reference */
299:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
300:   } else if (ishdf5) {
301: #if defined(PETSC_HAVE_HDF5)
302:     VecView_Plex_Local_HDF5_Internal(v, viewer);
303: #else
304:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
305: #endif
306:   } else if (isdraw) {
307:     VecView_Plex_Local_Draw(v, viewer);
308:   } else {
309:     if (isseq) {VecView_Seq(v, viewer);}
310:     else       {VecView_MPI(v, viewer);}
311:   }
312:   return(0);
313: }

315: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
316: {
317:   DM             dm;
318:   PetscReal      time = 0.0;
319:   PetscBool      isvtk, ishdf5, isdraw, isseq;

323:   VecGetDM(v, &dm);
324:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
325:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
326:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
327:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);
328:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
329:   if (isvtk) {
330:     Vec         locv;
331:     const char *name;

333:     DMGetLocalVector(dm, &locv);
334:     PetscObjectGetName((PetscObject) v, &name);
335:     PetscObjectSetName((PetscObject) locv, name);
336:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
337:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
338:     DMGetOutputSequenceNumber(dm, NULL, &time);
339:     DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
340:     VecView_Plex_Local(locv, viewer);
341:     DMRestoreLocalVector(dm, &locv);
342:   } else if (ishdf5) {
343: #if defined(PETSC_HAVE_HDF5)
344:     VecView_Plex_HDF5_Internal(v, viewer);
345: #else
346:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
347: #endif
348:   } else if (isdraw) {
349:     Vec         locv;
350:     const char *name;

352:     DMGetLocalVector(dm, &locv);
353:     PetscObjectGetName((PetscObject) v, &name);
354:     PetscObjectSetName((PetscObject) locv, name);
355:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
356:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
357:     DMGetOutputSequenceNumber(dm, NULL, &time);
358:     DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
359:     VecView_Plex_Local(locv, viewer);
360:     DMRestoreLocalVector(dm, &locv);
361:   } else {
362:     if (isseq) {VecView_Seq(v, viewer);}
363:     else       {VecView_MPI(v, viewer);}
364:   }
365:   return(0);
366: }

368: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
369: {
370:   DM                dm;
371:   MPI_Comm          comm;
372:   PetscViewerFormat format;
373:   Vec               v;
374:   PetscBool         isvtk, ishdf5;
375:   PetscErrorCode    ierr;

378:   VecGetDM(originalv, &dm);
379:   PetscObjectGetComm((PetscObject) originalv, &comm);
380:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
381:   PetscViewerGetFormat(viewer, &format);
382:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
383:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
384:   if (format == PETSC_VIEWER_NATIVE) {
385:     const char *vecname;
386:     PetscInt    n, nroots;

388:     if (dm->sfNatural) {
389:       VecGetLocalSize(originalv, &n);
390:       PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
391:       if (n == nroots) {
392:         DMGetGlobalVector(dm, &v);
393:         DMPlexGlobalToNaturalBegin(dm, originalv, v);
394:         DMPlexGlobalToNaturalEnd(dm, originalv, v);
395:         PetscObjectGetName((PetscObject) originalv, &vecname);
396:         PetscObjectSetName((PetscObject) v, vecname);
397:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
398:     } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
399:   } else {
400:     /* we are viewing a natural DMPlex vec. */
401:     v = originalv;
402:   }
403:   if (ishdf5) {
404: #if defined(PETSC_HAVE_HDF5)
405:     VecView_Plex_HDF5_Native_Internal(v, viewer);
406: #else
407:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
408: #endif
409:   } else if (isvtk) {
410:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
411:   } else {
412:     PetscBool isseq;

414:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
415:     if (isseq) {VecView_Seq(v, viewer);}
416:     else       {VecView_MPI(v, viewer);}
417:   }
418:   if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
419:   return(0);
420: }

422: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
423: {
424:   DM             dm;
425:   PetscBool      ishdf5;

429:   VecGetDM(v, &dm);
430:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
431:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
432:   if (ishdf5) {
433:     DM          dmBC;
434:     Vec         gv;
435:     const char *name;

437:     DMGetOutputDM(dm, &dmBC);
438:     DMGetGlobalVector(dmBC, &gv);
439:     PetscObjectGetName((PetscObject) v, &name);
440:     PetscObjectSetName((PetscObject) gv, name);
441:     VecLoad_Default(gv, viewer);
442:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
443:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
444:     DMRestoreGlobalVector(dmBC, &gv);
445:   } else {
446:     VecLoad_Default(v, viewer);
447:   }
448:   return(0);
449: }

451: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
452: {
453:   DM             dm;
454:   PetscBool      ishdf5;

458:   VecGetDM(v, &dm);
459:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
460:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
461:   if (ishdf5) {
462: #if defined(PETSC_HAVE_HDF5)
463:     VecLoad_Plex_HDF5_Internal(v, viewer);
464: #else
465:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
466: #endif
467:   } else {
468:     VecLoad_Default(v, viewer);
469:   }
470:   return(0);
471: }

473: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
474: {
475:   DM                dm;
476:   PetscViewerFormat format;
477:   PetscBool         ishdf5;
478:   PetscErrorCode    ierr;

481:   VecGetDM(originalv, &dm);
482:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
483:   PetscViewerGetFormat(viewer, &format);
484:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
485:   if (format == PETSC_VIEWER_NATIVE) {
486:     if (dm->sfNatural) {
487:       if (ishdf5) {
488: #if defined(PETSC_HAVE_HDF5)
489:         Vec         v;
490:         const char *vecname;

492:         DMGetGlobalVector(dm, &v);
493:         PetscObjectGetName((PetscObject) originalv, &vecname);
494:         PetscObjectSetName((PetscObject) v, vecname);
495:         VecLoad_Plex_HDF5_Native_Internal(v, viewer);
496:         DMPlexNaturalToGlobalBegin(dm, v, originalv);
497:         DMPlexNaturalToGlobalEnd(dm, v, originalv);
498:         DMRestoreGlobalVector(dm, &v);
499: #else
500:         SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
501: #endif
502:       } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
503:     }
504:   }
505:   return(0);
506: }

508: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
509: {
510:   PetscSection       coordSection;
511:   Vec                coordinates;
512:   DMLabel            depthLabel;
513:   const char        *name[4];
514:   const PetscScalar *a;
515:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
516:   PetscErrorCode     ierr;

519:   DMGetDimension(dm, &dim);
520:   DMGetCoordinatesLocal(dm, &coordinates);
521:   DMGetCoordinateSection(dm, &coordSection);
522:   DMPlexGetDepthLabel(dm, &depthLabel);
523:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
524:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
525:   VecGetArrayRead(coordinates, &a);
526:   name[0]     = "vertex";
527:   name[1]     = "edge";
528:   name[dim-1] = "face";
529:   name[dim]   = "cell";
530:   for (c = cStart; c < cEnd; ++c) {
531:     PetscInt *closure = NULL;
532:     PetscInt  closureSize, cl;

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

540:       if ((point < pStart) || (point >= pEnd)) continue;
541:       PetscSectionGetDof(coordSection, point, &dof);
542:       if (!dof) continue;
543:       DMLabelGetValue(depthLabel, point, &depth);
544:       PetscSectionGetOffset(coordSection, point, &off);
545:       PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
546:       for (p = 0; p < dof/dim; ++p) {
547:         PetscViewerASCIIPrintf(viewer, " (");
548:         for (d = 0; d < dim; ++d) {
549:           if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
550:           PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
551:         }
552:         PetscViewerASCIIPrintf(viewer, ")");
553:       }
554:       PetscViewerASCIIPrintf(viewer, "\n");
555:     }
556:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
557:     PetscViewerASCIIPopTab(viewer);
558:   }
559:   VecRestoreArrayRead(coordinates, &a);
560:   return(0);
561: }

563: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
564: {
565:   DM_Plex          *mesh = (DM_Plex*) dm->data;
566:   DM                cdm;
567:   DMLabel           markers;
568:   PetscSection      coordSection;
569:   Vec               coordinates;
570:   PetscViewerFormat format;
571:   PetscErrorCode    ierr;

574:   DMGetCoordinateDM(dm, &cdm);
575:   DMGetDefaultSection(cdm, &coordSection);
576:   DMGetCoordinatesLocal(dm, &coordinates);
577:   PetscViewerGetFormat(viewer, &format);
578:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
579:     const char *name;
580:     PetscInt    maxConeSize, maxSupportSize;
581:     PetscInt    pStart, pEnd, p;
582:     PetscMPIInt rank, size;

584:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
585:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
586:     PetscObjectGetName((PetscObject) dm, &name);
587:     DMPlexGetChart(dm, &pStart, &pEnd);
588:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
589:     PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);
590:     PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
591:     PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
592:     PetscViewerASCIIPushSynchronized(viewer);
593:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);
594:     for (p = pStart; p < pEnd; ++p) {
595:       PetscInt dof, off, s;

597:       PetscSectionGetDof(mesh->supportSection, p, &dof);
598:       PetscSectionGetOffset(mesh->supportSection, p, &off);
599:       for (s = off; s < off+dof; ++s) {
600:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
601:       }
602:     }
603:     PetscViewerFlush(viewer);
604:     PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
605:     for (p = pStart; p < pEnd; ++p) {
606:       PetscInt dof, off, c;

608:       PetscSectionGetDof(mesh->coneSection, p, &dof);
609:       PetscSectionGetOffset(mesh->coneSection, p, &off);
610:       for (c = off; c < off+dof; ++c) {
611:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
612:       }
613:     }
614:     PetscViewerFlush(viewer);
615:     PetscViewerASCIIPopSynchronized(viewer);
616:     PetscSectionGetChart(coordSection, &pStart, NULL);
617:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
618:     DMGetLabel(dm, "marker", &markers);
619:     DMLabelView(markers,viewer);
620:     if (size > 1) {
621:       PetscSF sf;

623:       DMGetPointSF(dm, &sf);
624:       PetscSFView(sf, viewer);
625:     }
626:     PetscViewerFlush(viewer);
627:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
628:     const char  *name, *color;
629:     const char  *defcolors[3]  = {"gray", "orange", "green"};
630:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
631:     PetscReal    scale         = 2.0;
632:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
633:     double       tcoords[3];
634:     PetscScalar *coords;
635:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
636:     PetscMPIInt  rank, size;
637:     char         **names, **colors, **lcolors;

639:     DMGetDimension(dm, &dim);
640:     DMPlexGetDepth(dm, &depth);
641:     DMGetNumLabels(dm, &numLabels);
642:     numLabels  = PetscMax(numLabels, 10);
643:     numColors  = 10;
644:     numLColors = 10;
645:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
646:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
647:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
648:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
649:     if (!useLabels) numLabels = 0;
650:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
651:     if (!useColors) {
652:       numColors = 3;
653:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
654:     }
655:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
656:     if (!useColors) {
657:       numLColors = 4;
658:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
659:     }
660:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
661:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
662:     PetscObjectGetName((PetscObject) dm, &name);
663:     PetscViewerASCIIPrintf(viewer, "\
664: \\documentclass[tikz]{standalone}\n\n\
665: \\usepackage{pgflibraryshapes}\n\
666: \\usetikzlibrary{backgrounds}\n\
667: \\usetikzlibrary{arrows}\n\
668: \\begin{document}\n");
669:     if (size > 1) {
670:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
671:       for (p = 0; p < size; ++p) {
672:         if (p > 0 && p == size-1) {
673:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
674:         } else if (p > 0) {
675:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
676:         }
677:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
678:       }
679:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
680:     }
681:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);
682:     /* Plot vertices */
683:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
684:     VecGetArray(coordinates, &coords);
685:     PetscViewerASCIIPushSynchronized(viewer);
686:     for (v = vStart; v < vEnd; ++v) {
687:       PetscInt  off, dof, d;
688:       PetscBool isLabeled = PETSC_FALSE;

690:       PetscSectionGetDof(coordSection, v, &dof);
691:       PetscSectionGetOffset(coordSection, v, &off);
692:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
693:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
694:       for (d = 0; d < dof; ++d) {
695:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
696:         tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
697:       }
698:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
699:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
700:       for (d = 0; d < dof; ++d) {
701:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
702:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
703:       }
704:       color = colors[rank%numColors];
705:       for (l = 0; l < numLabels; ++l) {
706:         PetscInt val;
707:         DMGetLabelValue(dm, names[l], v, &val);
708:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
709:       }
710:       if (useNumbers) {
711:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
712:       } else {
713:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
714:       }
715:     }
716:     VecRestoreArray(coordinates, &coords);
717:     PetscViewerFlush(viewer);
718:     /* Plot edges */
719:     if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
720:     if (dim < 3 && useNumbers) {
721:       VecGetArray(coordinates, &coords);
722:       PetscViewerASCIIPrintf(viewer, "\\path\n");
723:       for (e = eStart; e < eEnd; ++e) {
724:         const PetscInt *cone;
725:         PetscInt        coneSize, offA, offB, dof, d;

727:         DMPlexGetConeSize(dm, e, &coneSize);
728:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
729:         DMPlexGetCone(dm, e, &cone);
730:         PetscSectionGetDof(coordSection, cone[0], &dof);
731:         PetscSectionGetOffset(coordSection, cone[0], &offA);
732:         PetscSectionGetOffset(coordSection, cone[1], &offB);
733:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
734:         for (d = 0; d < dof; ++d) {
735:           tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
736:           tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
737:         }
738:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
739:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
740:         for (d = 0; d < dof; ++d) {
741:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
742:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
743:         }
744:         color = colors[rank%numColors];
745:         for (l = 0; l < numLabels; ++l) {
746:           PetscInt val;
747:           DMGetLabelValue(dm, names[l], v, &val);
748:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
749:         }
750:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
751:       }
752:       VecRestoreArray(coordinates, &coords);
753:       PetscViewerFlush(viewer);
754:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
755:     }
756:     /* Plot cells */
757:     if (dim == 3 || !useNumbers) {
758:       for (e = eStart; e < eEnd; ++e) {
759:         const PetscInt *cone;

761:         color = colors[rank%numColors];
762:         for (l = 0; l < numLabels; ++l) {
763:           PetscInt val;
764:           DMGetLabelValue(dm, names[l], e, &val);
765:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
766:         }
767:         DMPlexGetCone(dm, e, &cone);
768:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
769:       }
770:     } else {
771:       DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
772:       for (c = cStart; c < cEnd; ++c) {
773:         PetscInt *closure = NULL;
774:         PetscInt  closureSize, firstPoint = -1;

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

781:           if ((point < vStart) || (point >= vEnd)) continue;
782:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
783:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
784:           if (firstPoint < 0) firstPoint = point;
785:         }
786:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
787:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
788:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
789:       }
790:     }
791:     PetscViewerFlush(viewer);
792:     PetscViewerASCIIPopSynchronized(viewer);
793:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
794:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
795:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
796:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
797:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
798:     PetscFree3(names, colors, lcolors);
799:   } else {
800:     MPI_Comm    comm;
801:     PetscInt   *sizes, *hybsizes;
802:     PetscInt    locDepth, depth, dim, d, pMax[4];
803:     PetscInt    pStart, pEnd, p;
804:     PetscInt    numLabels, l;
805:     const char *name;
806:     PetscMPIInt size;

808:     PetscObjectGetComm((PetscObject)dm,&comm);
809:     MPI_Comm_size(comm, &size);
810:     DMGetDimension(dm, &dim);
811:     PetscObjectGetName((PetscObject) dm, &name);
812:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);}
813:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);}
814:     DMPlexGetDepth(dm, &locDepth);
815:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
816:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);
817:     PetscMalloc2(size,&sizes,size,&hybsizes);
818:     if (depth == 1) {
819:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
820:       pEnd = pEnd - pStart;
821:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
822:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
823:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
824:       PetscViewerASCIIPrintf(viewer, "\n");
825:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
826:       pEnd = pEnd - pStart;
827:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
828:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
829:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
830:       PetscViewerASCIIPrintf(viewer, "\n");
831:     } else {
832:       PetscMPIInt rank;
833:       MPI_Comm_rank(comm, &rank);
834:       for (d = 0; d <= dim; d++) {
835:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
836:         pEnd    -= pStart;
837:         pMax[d] -= pStart;
838:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
839:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
840:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
841:         for (p = 0; p < size; ++p) {
842:           if (!rank) {
843:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
844:             else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
845:           }
846:         }
847:         PetscViewerASCIIPrintf(viewer, "\n");
848:       }
849:     }
850:     PetscFree2(sizes,hybsizes);
851:     DMGetNumLabels(dm, &numLabels);
852:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
853:     for (l = 0; l < numLabels; ++l) {
854:       DMLabel         label;
855:       const char     *name;
856:       IS              valueIS;
857:       const PetscInt *values;
858:       PetscInt        numValues, v;

860:       DMGetLabelName(dm, l, &name);
861:       DMGetLabel(dm, name, &label);
862:       DMLabelGetNumValues(label, &numValues);
863:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata of sizes (", name, numValues);
864:       DMLabelGetValueIS(label, &valueIS);
865:       ISGetIndices(valueIS, &values);
866:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
867:       for (v = 0; v < numValues; ++v) {
868:         PetscInt size;

870:         DMLabelGetStratumSize(label, values[v], &size);
871:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
872:         PetscViewerASCIIPrintf(viewer, "%D", size);
873:       }
874:       PetscViewerASCIIPrintf(viewer, ")\n");
875:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
876:       ISRestoreIndices(valueIS, &values);
877:       ISDestroy(&valueIS);
878:     }
879:     DMGetCoarseDM(dm, &cdm);
880:     if (cdm) {
881:       PetscViewerASCIIPushTab(viewer);
882:       DMPlexView_Ascii(cdm, viewer);
883:       PetscViewerASCIIPopTab(viewer);
884:     }
885:   }
886:   return(0);
887: }

889: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
890: {
891:   PetscDraw          draw;
892:   DM                 cdm;
893:   PetscSection       coordSection;
894:   Vec                coordinates;
895:   const PetscScalar *coords;
896:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
897:   PetscBool          isnull;
898:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
899:   PetscErrorCode     ierr;

902:   DMGetCoordinateDim(dm, &dim);
903:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
904:   DMGetCoordinateDM(dm, &cdm);
905:   DMGetDefaultSection(cdm, &coordSection);
906:   DMGetCoordinatesLocal(dm, &coordinates);
907:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
908:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

910:   PetscViewerDrawGetDraw(viewer, 0, &draw);
911:   PetscDrawIsNull(draw, &isnull);
912:   if (isnull) return(0);
913:   PetscDrawSetTitle(draw, "Mesh");

915:   VecGetLocalSize(coordinates, &N);
916:   VecGetArrayRead(coordinates, &coords);
917:   for (c = 0; c < N; c += dim) {
918:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
919:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
920:   }
921:   VecRestoreArrayRead(coordinates, &coords);
922:   PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);
923:   PetscDrawClear(draw);

925:   for (c = cStart; c < cEnd; ++c) {
926:     PetscScalar *coords = NULL;
927:     PetscInt     numCoords;

929:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
930:     switch (numCoords) {
931:     case 6:
932:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
933:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
934:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
935:       break;
936:     case 8:
937:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
938:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
939:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
940:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
941:       break;
942:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
943:     }
944:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
945:   }
946:   PetscDrawFlush(draw);
947:   PetscDrawPause(draw);
948:   PetscDrawSave(draw);
949:   return(0);
950: }

952: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
953: {
954:   PetscBool      iascii, ishdf5, isvtk, isdraw;

960:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
961:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
962:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
963:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
964:   if (iascii) {
965:     DMPlexView_Ascii(dm, viewer);
966:   } else if (ishdf5) {
967: #if defined(PETSC_HAVE_HDF5)
968:     PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
969:     DMPlexView_HDF5_Internal(dm, viewer);
970:     PetscViewerPopFormat(viewer);
971: #else
972:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
973: #endif
974:   } else if (isvtk) {
975:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
976:   } else if (isdraw) {
977:     DMPlexView_Draw(dm, viewer);
978:   }
979:   return(0);
980: }

982: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
983: {
984:   PetscBool      isbinary, ishdf5;

990:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
991:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
992:   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
993:   else if (ishdf5) {
994: #if defined(PETSC_HAVE_HDF5)
995:     DMPlexLoad_HDF5_Internal(dm, viewer);
996: #else
997:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
998: #endif
999:   }
1000:   return(0);
1001: }

1003: PetscErrorCode DMDestroy_Plex(DM dm)
1004: {
1005:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1009:   if (--mesh->refct > 0) return(0);
1010:   PetscSectionDestroy(&mesh->coneSection);
1011:   PetscFree(mesh->cones);
1012:   PetscFree(mesh->coneOrientations);
1013:   PetscSectionDestroy(&mesh->supportSection);
1014:   PetscSectionDestroy(&mesh->subdomainSection);
1015:   PetscFree(mesh->supports);
1016:   PetscFree(mesh->facesTmp);
1017:   PetscFree(mesh->tetgenOpts);
1018:   PetscFree(mesh->triangleOpts);
1019:   PetscPartitionerDestroy(&mesh->partitioner);
1020:   DMLabelDestroy(&mesh->subpointMap);
1021:   ISDestroy(&mesh->globalVertexNumbers);
1022:   ISDestroy(&mesh->globalCellNumbers);
1023:   PetscSectionDestroy(&mesh->anchorSection);
1024:   ISDestroy(&mesh->anchorIS);
1025:   PetscSectionDestroy(&mesh->parentSection);
1026:   PetscFree(mesh->parents);
1027:   PetscFree(mesh->childIDs);
1028:   PetscSectionDestroy(&mesh->childSection);
1029:   PetscFree(mesh->children);
1030:   DMDestroy(&mesh->referenceTree);
1031:   PetscGridHashDestroy(&mesh->lbox);
1032:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1033:   PetscFree(mesh);
1034:   PetscObjectComposeFunction((PetscObject)dm,"DMAdaptLabel_C",NULL);
1035:   return(0);
1036: }

1038: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1039: {
1040:   PetscSection           sectionGlobal;
1041:   PetscInt               bs = -1, mbs;
1042:   PetscInt               localSize;
1043:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1044:   PetscErrorCode         ierr;
1045:   MatType                mtype;
1046:   ISLocalToGlobalMapping ltog;

1049:   MatInitializePackage();
1050:   mtype = dm->mattype;
1051:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
1052:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1053:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1054:   MatCreate(PetscObjectComm((PetscObject)dm), J);
1055:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1056:   MatSetType(*J, mtype);
1057:   MatSetFromOptions(*J);
1058:   MatGetBlockSize(*J, &mbs);
1059:   if (mbs > 1) bs = mbs;
1060:   PetscStrcmp(mtype, MATSHELL, &isShell);
1061:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
1062:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1063:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1064:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1065:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1066:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1067:   PetscStrcmp(mtype, MATIS, &isMatIS);
1068:   if (!isShell) {
1069:     PetscSection subSection;
1070:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1071:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin, *ltogidx, lsize;
1072:     PetscInt     pStart, pEnd, p, dof, cdof;

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

1079:       DMGetDefaultSection(dm, &section);
1080:       PetscSectionGetStorageSize(section, &size);
1081:       PetscMalloc1(size,&ltogidx);
1082:       DMPlexGetSubdomainSection(dm, &subSection);
1083:     } else {
1084:       DMGetLocalToGlobalMapping(dm,&ltog);
1085:     }
1086:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1087:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1088:       PetscInt bdof;

1090:       PetscSectionGetDof(sectionGlobal, p, &dof);
1091:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1092:       dof  = dof < 0 ? -(dof+1) : dof;
1093:       bdof = cdof && (dof-cdof) ? 1 : dof;
1094:       if (dof) {
1095:         if (bs < 0)          {bs = bdof;}
1096:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1097:       }
1098:       if (isMatIS) {
1099:         PetscInt loff,c,off;
1100:         PetscSectionGetOffset(subSection, p, &loff);
1101:         PetscSectionGetOffset(sectionGlobal, p, &off);
1102:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1103:       }
1104:     }
1105:     /* Must have same blocksize on all procs (some might have no points) */
1106:     bsLocal = bs;
1107:     MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1108:     bsLocal = bs < 0 ? bsMax : bs;
1109:     MPIU_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
1110:     if (bsMin != bsMax) {bs = 1;}
1111:     else                {bs = bsMax;}
1112:     bs   = bs < 0 ? 1 : bs;
1113:     if (isMatIS) {
1114:       PetscInt l;
1115:       /* Must reduce indices by blocksize */
1116:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1117:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1118:     }
1119:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1120:     if (isMatIS) {
1121:       ISLocalToGlobalMappingDestroy(&ltog);
1122:     }
1123:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1124:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1125:     PetscFree4(dnz, onz, dnzu, onzu);
1126:   }
1127:   MatSetDM(*J, dm);
1128:   return(0);
1129: }

1131: /*@
1132:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1134:   Not collective

1136:   Input Parameter:
1137: . mesh - The DMPlex

1139:   Output Parameters:
1140: . subsection - The subdomain section

1142:   Level: developer

1144: .seealso:
1145: @*/
1146: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1147: {
1148:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1153:   if (!mesh->subdomainSection) {
1154:     PetscSection section;
1155:     PetscSF      sf;

1157:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1158:     DMGetDefaultSection(dm,&section);
1159:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1160:     PetscSFDestroy(&sf);
1161:   }
1162:   *subsection = mesh->subdomainSection;
1163:   return(0);
1164: }

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

1169:   Not collective

1171:   Input Parameter:
1172: . mesh - The DMPlex

1174:   Output Parameters:
1175: + pStart - The first mesh point
1176: - pEnd   - The upper bound for mesh points

1178:   Level: beginner

1180: .seealso: DMPlexCreate(), DMPlexSetChart()
1181: @*/
1182: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1183: {
1184:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1189:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1190:   return(0);
1191: }

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

1196:   Not collective

1198:   Input Parameters:
1199: + mesh - The DMPlex
1200: . pStart - The first mesh point
1201: - pEnd   - The upper bound for mesh points

1203:   Output Parameters:

1205:   Level: beginner

1207: .seealso: DMPlexCreate(), DMPlexGetChart()
1208: @*/
1209: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1210: {
1211:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1216:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1217:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1218:   return(0);
1219: }

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

1224:   Not collective

1226:   Input Parameters:
1227: + mesh - The DMPlex
1228: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1230:   Output Parameter:
1231: . size - The cone size for point p

1233:   Level: beginner

1235: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1236: @*/
1237: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1238: {
1239:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1245:   PetscSectionGetDof(mesh->coneSection, p, size);
1246:   return(0);
1247: }

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

1252:   Not collective

1254:   Input Parameters:
1255: + mesh - The DMPlex
1256: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1257: - size - The cone size for point p

1259:   Output Parameter:

1261:   Note:
1262:   This should be called after DMPlexSetChart().

1264:   Level: beginner

1266: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1267: @*/
1268: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1269: {
1270:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1277:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1278:   return(0);
1279: }

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

1284:   Not collective

1286:   Input Parameters:
1287: + mesh - The DMPlex
1288: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1289: - size - The additional cone size for point p

1291:   Output Parameter:

1293:   Note:
1294:   This should be called after DMPlexSetChart().

1296:   Level: beginner

1298: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1299: @*/
1300: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1301: {
1302:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1303:   PetscInt       csize;

1308:   PetscSectionAddDof(mesh->coneSection, p, size);
1309:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1311:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1312:   return(0);
1313: }

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

1318:   Not collective

1320:   Input Parameters:
1321: + mesh - The DMPlex
1322: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1327:   Level: beginner

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

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

1335: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1336: @*/
1337: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1338: {
1339:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1340:   PetscInt       off;

1346:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1347:   *cone = &mesh->cones[off];
1348:   return(0);
1349: }

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

1354:   Not collective

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

1361:   Output Parameter:

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

1366:   Level: beginner

1368: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1369: @*/
1370: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1371: {
1372:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1373:   PetscInt       pStart, pEnd;
1374:   PetscInt       dof, off, c;

1379:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1380:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1382:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1383:   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);
1384:   for (c = 0; c < dof; ++c) {
1385:     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);
1386:     mesh->cones[off+c] = cone[c];
1387:   }
1388:   return(0);
1389: }

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

1394:   Not collective

1396:   Input Parameters:
1397: + mesh - The DMPlex
1398: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1406:   Level: beginner

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

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

1414: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1415: @*/
1416: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1417: {
1418:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1419:   PetscInt       off;

1424: #if defined(PETSC_USE_DEBUG)
1425:   {
1426:     PetscInt dof;
1427:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1429:   }
1430: #endif
1431:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1433:   *coneOrientation = &mesh->coneOrientations[off];
1434:   return(0);
1435: }

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

1440:   Not collective

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

1450:   Output Parameter:

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

1455:   Level: beginner

1457: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1458: @*/
1459: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1460: {
1461:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1462:   PetscInt       pStart, pEnd;
1463:   PetscInt       dof, off, c;

1468:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1469:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1471:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1472:   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);
1473:   for (c = 0; c < dof; ++c) {
1474:     PetscInt cdof, o = coneOrientation[c];

1476:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1477:     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);
1478:     mesh->coneOrientations[off+c] = o;
1479:   }
1480:   return(0);
1481: }

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

1486:   Not collective

1488:   Input Parameters:
1489: + mesh - The DMPlex
1490: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1491: . conePos - The local index in the cone where the point should be put
1492: - conePoint - The mesh point to insert

1494:   Level: beginner

1496: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1497: @*/
1498: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1499: {
1500:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1501:   PetscInt       pStart, pEnd;
1502:   PetscInt       dof, off;

1507:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1508:   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);
1509:   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);
1510:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1511:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1512:   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);
1513:   mesh->cones[off+conePos] = conePoint;
1514:   return(0);
1515: }

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

1520:   Not collective

1522:   Input Parameters:
1523: + mesh - The DMPlex
1524: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1525: . conePos - The local index in the cone where the point should be put
1526: - coneOrientation - The point orientation to insert

1528:   Level: beginner

1530: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1531: @*/
1532: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1533: {
1534:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1535:   PetscInt       pStart, pEnd;
1536:   PetscInt       dof, off;

1541:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
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:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1544:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1545:   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);
1546:   mesh->coneOrientations[off+conePos] = coneOrientation;
1547:   return(0);
1548: }

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

1553:   Not collective

1555:   Input Parameters:
1556: + mesh - The DMPlex
1557: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1559:   Output Parameter:
1560: . size - The support size for point p

1562:   Level: beginner

1564: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1565: @*/
1566: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1567: {
1568:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1574:   PetscSectionGetDof(mesh->supportSection, p, size);
1575:   return(0);
1576: }

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

1581:   Not collective

1583:   Input Parameters:
1584: + mesh - The DMPlex
1585: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1586: - size - The support size for point p

1588:   Output Parameter:

1590:   Note:
1591:   This should be called after DMPlexSetChart().

1593:   Level: beginner

1595: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1596: @*/
1597: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1598: {
1599:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1606:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1607:   return(0);
1608: }

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

1613:   Not collective

1615:   Input Parameters:
1616: + mesh - The DMPlex
1617: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1622:   Level: beginner

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

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

1630: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1631: @*/
1632: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1633: {
1634:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1635:   PetscInt       off;

1641:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1642:   *support = &mesh->supports[off];
1643:   return(0);
1644: }

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

1649:   Not collective

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

1656:   Output Parameter:

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

1661:   Level: beginner

1663: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1664: @*/
1665: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1666: {
1667:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1668:   PetscInt       pStart, pEnd;
1669:   PetscInt       dof, off, c;

1674:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1675:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1677:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1678:   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);
1679:   for (c = 0; c < dof; ++c) {
1680:     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);
1681:     mesh->supports[off+c] = support[c];
1682:   }
1683:   return(0);
1684: }

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

1689:   Not collective

1691:   Input Parameters:
1692: + mesh - The DMPlex
1693: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1694: . supportPos - The local index in the cone where the point should be put
1695: - supportPoint - The mesh point to insert

1697:   Level: beginner

1699: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1700: @*/
1701: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1702: {
1703:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1704:   PetscInt       pStart, pEnd;
1705:   PetscInt       dof, off;

1710:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1711:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1712:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1713:   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);
1714:   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);
1715:   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);
1716:   mesh->supports[off+supportPos] = supportPoint;
1717:   return(0);
1718: }

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

1723:   Not collective

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

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

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

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

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

1744:   Level: beginner

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

1760:   DMPlexGetDepth(dm, &depth);
1761:   /* This is only 1-level */
1762:   if (useCone) {
1763:     DMPlexGetConeSize(dm, p, &tmpSize);
1764:     DMPlexGetCone(dm, p, &tmp);
1765:     DMPlexGetConeOrientation(dm, p, &tmpO);
1766:   } else {
1767:     DMPlexGetSupportSize(dm, p, &tmpSize);
1768:     DMPlexGetSupport(dm, p, &tmp);
1769:   }
1770:   if (depth == 1) {
1771:     if (*points) {
1772:       closure = *points;
1773:     } else {
1774:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1775:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1776:     }
1777:     closure[0] = p; closure[1] = 0;
1778:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1779:       closure[closureSize]   = tmp[t];
1780:       closure[closureSize+1] = tmpO ? tmpO[t] : 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] = 0;
1802:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1803:     const PetscInt cp = tmp[t];
1804:     const PetscInt co = tmpO ? tmpO[t] : 0;

1806:     closure[closureSize]   = cp;
1807:     closure[closureSize+1] = co;
1808:     fifo[fifoSize]         = cp;
1809:     fifo[fifoSize+1]       = co;
1810:   }
1811:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1812:   while (fifoSize - fifoStart) {
1813:     const PetscInt q   = fifo[fifoStart];
1814:     const PetscInt o   = fifo[fifoStart+1];
1815:     const PetscInt rev = o >= 0 ? 0 : 1;
1816:     const PetscInt off = rev ? -(o+1) : o;

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

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

1863: /*@C
1864:   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

1866:   Not collective

1868:   Input Parameters:
1869: + mesh - The DMPlex
1870: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1871: . orientation - The orientation of the point
1872: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1873: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

1888:   Level: beginner

1890: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1891: @*/
1892: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1893: {
1894:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1895:   PetscInt       *closure, *fifo;
1896:   const PetscInt *tmp = NULL, *tmpO = NULL;
1897:   PetscInt        tmpSize, t;
1898:   PetscInt        depth       = 0, maxSize;
1899:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1900:   PetscErrorCode  ierr;

1904:   DMPlexGetDepth(dm, &depth);
1905:   /* This is only 1-level */
1906:   if (useCone) {
1907:     DMPlexGetConeSize(dm, p, &tmpSize);
1908:     DMPlexGetCone(dm, p, &tmp);
1909:     DMPlexGetConeOrientation(dm, p, &tmpO);
1910:   } else {
1911:     DMPlexGetSupportSize(dm, p, &tmpSize);
1912:     DMPlexGetSupport(dm, p, &tmp);
1913:   }
1914:   if (depth == 1) {
1915:     if (*points) {
1916:       closure = *points;
1917:     } else {
1918:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1919:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1920:     }
1921:     closure[0] = p; closure[1] = ornt;
1922:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1923:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1924:       closure[closureSize]   = tmp[i];
1925:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1926:     }
1927:     if (numPoints) *numPoints = closureSize/2;
1928:     if (points)    *points    = closure;
1929:     return(0);
1930:   }
1931:   {
1932:     PetscInt c, coneSeries, s,supportSeries;

1934:     c = mesh->maxConeSize;
1935:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1936:     s = mesh->maxSupportSize;
1937:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1938:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1939:   }
1940:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1941:   if (*points) {
1942:     closure = *points;
1943:   } else {
1944:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1945:   }
1946:   closure[0] = p; closure[1] = ornt;
1947:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1948:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1949:     const PetscInt cp = tmp[i];
1950:     PetscInt       co = tmpO ? tmpO[i] : 0;

1952:     if (ornt < 0) {
1953:       PetscInt childSize, coff;
1954:       DMPlexGetConeSize(dm, cp, &childSize);
1955:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
1956:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1957:     }
1958:     closure[closureSize]   = cp;
1959:     closure[closureSize+1] = co;
1960:     fifo[fifoSize]         = cp;
1961:     fifo[fifoSize+1]       = co;
1962:   }
1963:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1964:   while (fifoSize - fifoStart) {
1965:     const PetscInt q   = fifo[fifoStart];
1966:     const PetscInt o   = fifo[fifoStart+1];
1967:     const PetscInt rev = o >= 0 ? 0 : 1;
1968:     const PetscInt off = rev ? -(o+1) : o;

1970:     if (useCone) {
1971:       DMPlexGetConeSize(dm, q, &tmpSize);
1972:       DMPlexGetCone(dm, q, &tmp);
1973:       DMPlexGetConeOrientation(dm, q, &tmpO);
1974:     } else {
1975:       DMPlexGetSupportSize(dm, q, &tmpSize);
1976:       DMPlexGetSupport(dm, q, &tmp);
1977:       tmpO = NULL;
1978:     }
1979:     for (t = 0; t < tmpSize; ++t) {
1980:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1981:       const PetscInt cp = tmp[i];
1982:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1983:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1984:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1985:       PetscInt       co = tmpO ? tmpO[i] : 0;
1986:       PetscInt       c;

1988:       if (rev) {
1989:         PetscInt childSize, coff;
1990:         DMPlexGetConeSize(dm, cp, &childSize);
1991:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1992:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1993:       }
1994:       /* Check for duplicate */
1995:       for (c = 0; c < closureSize; c += 2) {
1996:         if (closure[c] == cp) break;
1997:       }
1998:       if (c == closureSize) {
1999:         closure[closureSize]   = cp;
2000:         closure[closureSize+1] = co;
2001:         fifo[fifoSize]         = cp;
2002:         fifo[fifoSize+1]       = co;
2003:         closureSize           += 2;
2004:         fifoSize              += 2;
2005:       }
2006:     }
2007:     fifoStart += 2;
2008:   }
2009:   if (numPoints) *numPoints = closureSize/2;
2010:   if (points)    *points    = closure;
2011:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
2012:   return(0);
2013: }

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

2018:   Not collective

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

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

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

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

2036:   Level: beginner

2038: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2039: @*/
2040: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2041: {

2048:   DMRestoreWorkArray(dm, 0, PETSC_INT, points);
2049:   if (numPoints) *numPoints = 0;
2050:   return(0);
2051: }

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

2056:   Not collective

2058:   Input Parameter:
2059: . mesh - The DMPlex

2061:   Output Parameters:
2062: + maxConeSize - The maximum number of in-edges
2063: - maxSupportSize - The maximum number of out-edges

2065:   Level: beginner

2067: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2068: @*/
2069: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2070: {
2071:   DM_Plex *mesh = (DM_Plex*) dm->data;

2075:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2076:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2077:   return(0);
2078: }

2080: PetscErrorCode DMSetUp_Plex(DM dm)
2081: {
2082:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2083:   PetscInt       size;

2088:   PetscSectionSetUp(mesh->coneSection);
2089:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2090:   PetscMalloc1(size, &mesh->cones);
2091:   PetscCalloc1(size, &mesh->coneOrientations);
2092:   if (mesh->maxSupportSize) {
2093:     PetscSectionSetUp(mesh->supportSection);
2094:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2095:     PetscMalloc1(size, &mesh->supports);
2096:   }
2097:   return(0);
2098: }

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

2105:   if (subdm) {DMClone(dm, subdm);}
2106:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2107:   return(0);
2108: }

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

2113:   Not collective

2115:   Input Parameter:
2116: . mesh - The DMPlex

2118:   Output Parameter:

2120:   Note:
2121:   This should be called after all calls to DMPlexSetCone()

2123:   Level: beginner

2125: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2126: @*/
2127: PetscErrorCode DMPlexSymmetrize(DM dm)
2128: {
2129:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2130:   PetscInt      *offsets;
2131:   PetscInt       supportSize;
2132:   PetscInt       pStart, pEnd, p;

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

2143:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2144:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2145:     for (c = off; c < off+dof; ++c) {
2146:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2147:     }
2148:   }
2149:   for (p = pStart; p < pEnd; ++p) {
2150:     PetscInt dof;

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

2154:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2155:   }
2156:   PetscSectionSetUp(mesh->supportSection);
2157:   /* Calculate supports */
2158:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2159:   PetscMalloc1(supportSize, &mesh->supports);
2160:   PetscCalloc1(pEnd - pStart, &offsets);
2161:   for (p = pStart; p < pEnd; ++p) {
2162:     PetscInt dof, off, c;

2164:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2165:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2166:     for (c = off; c < off+dof; ++c) {
2167:       const PetscInt q = mesh->cones[c];
2168:       PetscInt       offS;

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

2172:       mesh->supports[offS+offsets[q]] = p;
2173:       ++offsets[q];
2174:     }
2175:   }
2176:   PetscFree(offsets);
2177:   return(0);
2178: }

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

2186:   Collective on dm

2188:   Input Parameter:
2189: . mesh - The DMPlex

2191:   Output Parameter:

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

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

2201:   Level: beginner

2203: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2204: @*/
2205: PetscErrorCode DMPlexStratify(DM dm)
2206: {
2207:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2208:   DMLabel        label;
2209:   PetscInt       pStart, pEnd, p;
2210:   PetscInt       numRoots = 0, numLeaves = 0;

2215:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2216:   /* Calculate depth */
2217:   DMPlexGetChart(dm, &pStart, &pEnd);
2218:   DMCreateLabel(dm, "depth");
2219:   DMPlexGetDepthLabel(dm, &label);
2220:   /* Initialize roots and count leaves */
2221:   for (p = pStart; p < pEnd; ++p) {
2222:     PetscInt coneSize, supportSize;

2224:     DMPlexGetConeSize(dm, p, &coneSize);
2225:     DMPlexGetSupportSize(dm, p, &supportSize);
2226:     if (!coneSize && supportSize) {
2227:       ++numRoots;
2228:       DMLabelSetValue(label, p, 0);
2229:     } else if (!supportSize && coneSize) {
2230:       ++numLeaves;
2231:     } else if (!supportSize && !coneSize) {
2232:       /* Isolated points */
2233:       DMLabelSetValue(label, p, 0);
2234:     }
2235:   }
2236:   if (numRoots + numLeaves == (pEnd - pStart)) {
2237:     for (p = pStart; p < pEnd; ++p) {
2238:       PetscInt coneSize, supportSize;

2240:       DMPlexGetConeSize(dm, p, &coneSize);
2241:       DMPlexGetSupportSize(dm, p, &supportSize);
2242:       if (!supportSize && coneSize) {
2243:         DMLabelSetValue(label, p, 1);
2244:       }
2245:     }
2246:   } else {
2247:     IS       pointIS;
2248:     PetscInt numPoints = 0, level = 0;

2250:     DMLabelGetStratumIS(label, level, &pointIS);
2251:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2252:     while (numPoints) {
2253:       const PetscInt *points;
2254:       const PetscInt  newLevel = level+1;

2256:       ISGetIndices(pointIS, &points);
2257:       for (p = 0; p < numPoints; ++p) {
2258:         const PetscInt  point = points[p];
2259:         const PetscInt *support;
2260:         PetscInt        supportSize, s;

2262:         DMPlexGetSupportSize(dm, point, &supportSize);
2263:         DMPlexGetSupport(dm, point, &support);
2264:         for (s = 0; s < supportSize; ++s) {
2265:           DMLabelSetValue(label, support[s], newLevel);
2266:         }
2267:       }
2268:       ISRestoreIndices(pointIS, &points);
2269:       ++level;
2270:       ISDestroy(&pointIS);
2271:       DMLabelGetStratumIS(label, level, &pointIS);
2272:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2273:       else         {numPoints = 0;}
2274:     }
2275:     ISDestroy(&pointIS);
2276:   }
2277:   { /* just in case there is an empty process */
2278:     PetscInt numValues, maxValues = 0, v;

2280:     DMLabelGetNumValues(label,&numValues);
2281:     for (v = 0; v < numValues; v++) {
2282:       IS pointIS;

2284:       DMLabelGetStratumIS(label, v, &pointIS);
2285:       if (pointIS) {
2286:         PetscInt  min, max, numPoints;
2287:         PetscInt  start;
2288:         PetscBool contig;

2290:         ISGetLocalSize(pointIS, &numPoints);
2291:         ISGetMinMax(pointIS, &min, &max);
2292:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2293:         if (start == 0 && contig) {
2294:           ISDestroy(&pointIS);
2295:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2296:           DMLabelSetStratumIS(label, v, pointIS);
2297:         }
2298:       }
2299:       ISDestroy(&pointIS);
2300:     }
2301:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2302:     for (v = numValues; v < maxValues; v++) {
2303:       DMLabelAddStratum(label,v);
2304:     }
2305:   }

2307:   DMLabelGetState(label, &mesh->depthState);
2308:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2309:   return(0);
2310: }

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

2315:   Not Collective

2317:   Input Parameters:
2318: + dm - The DMPlex object
2319: . numPoints - The number of input points for the join
2320: - points - The input points

2322:   Output Parameters:
2323: + numCoveredPoints - The number of points in the join
2324: - coveredPoints - The points in the join

2326:   Level: intermediate

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

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

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

2336: .keywords: mesh
2337: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2338: @*/
2339: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2340: {
2341:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2342:   PetscInt      *join[2];
2343:   PetscInt       joinSize, i = 0;
2344:   PetscInt       dof, off, p, c, m;

2352:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
2353:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
2354:   /* Copy in support of first point */
2355:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2356:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2357:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2358:     join[i][joinSize] = mesh->supports[off+joinSize];
2359:   }
2360:   /* Check each successive support */
2361:   for (p = 1; p < numPoints; ++p) {
2362:     PetscInt newJoinSize = 0;

2364:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2365:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2366:     for (c = 0; c < dof; ++c) {
2367:       const PetscInt point = mesh->supports[off+c];

2369:       for (m = 0; m < joinSize; ++m) {
2370:         if (point == join[i][m]) {
2371:           join[1-i][newJoinSize++] = point;
2372:           break;
2373:         }
2374:       }
2375:     }
2376:     joinSize = newJoinSize;
2377:     i        = 1-i;
2378:   }
2379:   *numCoveredPoints = joinSize;
2380:   *coveredPoints    = join[i];
2381:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2382:   return(0);
2383: }

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

2388:   Not Collective

2390:   Input Parameters:
2391: + dm - The DMPlex object
2392: . numPoints - The number of input points for the join
2393: - points - The input points

2395:   Output Parameters:
2396: + numCoveredPoints - The number of points in the join
2397: - coveredPoints - The points in the join

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

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

2405:   Level: intermediate

2407: .keywords: mesh
2408: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2409: @*/
2410: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2411: {

2419:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2420:   if (numCoveredPoints) *numCoveredPoints = 0;
2421:   return(0);
2422: }

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

2427:   Not Collective

2429:   Input Parameters:
2430: + dm - The DMPlex object
2431: . numPoints - The number of input points for the join
2432: - points - The input points

2434:   Output Parameters:
2435: + numCoveredPoints - The number of points in the join
2436: - coveredPoints - The points in the join

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

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

2444:   Level: intermediate

2446: .keywords: mesh
2447: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2448: @*/
2449: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2450: {
2451:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2452:   PetscInt      *offsets, **closures;
2453:   PetscInt      *join[2];
2454:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2455:   PetscInt       p, d, c, m, ms;


2464:   DMPlexGetDepth(dm, &depth);
2465:   PetscCalloc1(numPoints, &closures);
2466:   DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2467:   ms      = mesh->maxSupportSize;
2468:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2469:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
2470:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);

2472:   for (p = 0; p < numPoints; ++p) {
2473:     PetscInt closureSize;

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

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

2481:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2482:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2483:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2484:           offsets[p*(depth+2)+d+1] = i;
2485:           break;
2486:         }
2487:       }
2488:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2489:     }
2490:     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);
2491:   }
2492:   for (d = 0; d < depth+1; ++d) {
2493:     PetscInt dof;

2495:     /* Copy in support of first point */
2496:     dof = offsets[d+1] - offsets[d];
2497:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2498:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2499:     }
2500:     /* Check each successive cone */
2501:     for (p = 1; p < numPoints && joinSize; ++p) {
2502:       PetscInt newJoinSize = 0;

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

2508:         for (m = 0; m < joinSize; ++m) {
2509:           if (point == join[i][m]) {
2510:             join[1-i][newJoinSize++] = point;
2511:             break;
2512:           }
2513:         }
2514:       }
2515:       joinSize = newJoinSize;
2516:       i        = 1-i;
2517:     }
2518:     if (joinSize) break;
2519:   }
2520:   *numCoveredPoints = joinSize;
2521:   *coveredPoints    = join[i];
2522:   for (p = 0; p < numPoints; ++p) {
2523:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2524:   }
2525:   PetscFree(closures);
2526:   DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2527:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2528:   return(0);
2529: }

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

2534:   Not Collective

2536:   Input Parameters:
2537: + dm - The DMPlex object
2538: . numPoints - The number of input points for the meet
2539: - points - The input points

2541:   Output Parameters:
2542: + numCoveredPoints - The number of points in the meet
2543: - coveredPoints - The points in the meet

2545:   Level: intermediate

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

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

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

2555: .keywords: mesh
2556: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2557: @*/
2558: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2559: {
2560:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2561:   PetscInt      *meet[2];
2562:   PetscInt       meetSize, i = 0;
2563:   PetscInt       dof, off, p, c, m;

2571:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
2572:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
2573:   /* Copy in cone of first point */
2574:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2575:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2576:   for (meetSize = 0; meetSize < dof; ++meetSize) {
2577:     meet[i][meetSize] = mesh->cones[off+meetSize];
2578:   }
2579:   /* Check each successive cone */
2580:   for (p = 1; p < numPoints; ++p) {
2581:     PetscInt newMeetSize = 0;

2583:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2584:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2585:     for (c = 0; c < dof; ++c) {
2586:       const PetscInt point = mesh->cones[off+c];

2588:       for (m = 0; m < meetSize; ++m) {
2589:         if (point == meet[i][m]) {
2590:           meet[1-i][newMeetSize++] = point;
2591:           break;
2592:         }
2593:       }
2594:     }
2595:     meetSize = newMeetSize;
2596:     i        = 1-i;
2597:   }
2598:   *numCoveringPoints = meetSize;
2599:   *coveringPoints    = meet[i];
2600:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2601:   return(0);
2602: }

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

2607:   Not Collective

2609:   Input Parameters:
2610: + dm - The DMPlex object
2611: . numPoints - The number of input points for the meet
2612: - points - The input points

2614:   Output Parameters:
2615: + numCoveredPoints - The number of points in the meet
2616: - coveredPoints - The points in the meet

2618:   Level: intermediate

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

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

2626: .keywords: mesh
2627: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2628: @*/
2629: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2630: {

2638:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2639:   if (numCoveredPoints) *numCoveredPoints = 0;
2640:   return(0);
2641: }

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

2646:   Not Collective

2648:   Input Parameters:
2649: + dm - The DMPlex object
2650: . numPoints - The number of input points for the meet
2651: - points - The input points

2653:   Output Parameters:
2654: + numCoveredPoints - The number of points in the meet
2655: - coveredPoints - The points in the meet

2657:   Level: intermediate

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

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

2665: .keywords: mesh
2666: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2667: @*/
2668: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2669: {
2670:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2671:   PetscInt      *offsets, **closures;
2672:   PetscInt      *meet[2];
2673:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2674:   PetscInt       p, h, c, m, mc;


2683:   DMPlexGetDepth(dm, &height);
2684:   PetscMalloc1(numPoints, &closures);
2685:   DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2686:   mc      = mesh->maxConeSize;
2687:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2688:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
2689:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);

2691:   for (p = 0; p < numPoints; ++p) {
2692:     PetscInt closureSize;

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

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

2700:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2701:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2702:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2703:           offsets[p*(height+2)+h+1] = i;
2704:           break;
2705:         }
2706:       }
2707:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2708:     }
2709:     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);
2710:   }
2711:   for (h = 0; h < height+1; ++h) {
2712:     PetscInt dof;

2714:     /* Copy in cone of first point */
2715:     dof = offsets[h+1] - offsets[h];
2716:     for (meetSize = 0; meetSize < dof; ++meetSize) {
2717:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2718:     }
2719:     /* Check each successive cone */
2720:     for (p = 1; p < numPoints && meetSize; ++p) {
2721:       PetscInt newMeetSize = 0;

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

2727:         for (m = 0; m < meetSize; ++m) {
2728:           if (point == meet[i][m]) {
2729:             meet[1-i][newMeetSize++] = point;
2730:             break;
2731:           }
2732:         }
2733:       }
2734:       meetSize = newMeetSize;
2735:       i        = 1-i;
2736:     }
2737:     if (meetSize) break;
2738:   }
2739:   *numCoveredPoints = meetSize;
2740:   *coveredPoints    = meet[i];
2741:   for (p = 0; p < numPoints; ++p) {
2742:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2743:   }
2744:   PetscFree(closures);
2745:   DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2746:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2747:   return(0);
2748: }

2750: /*@C
2751:   DMPlexEqual - Determine if two DMs have the same topology

2753:   Not Collective

2755:   Input Parameters:
2756: + dmA - A DMPlex object
2757: - dmB - A DMPlex object

2759:   Output Parameters:
2760: . equal - PETSC_TRUE if the topologies are identical

2762:   Level: intermediate

2764:   Notes:
2765:   We are not solving graph isomorphism, so we do not permutation.

2767: .keywords: mesh
2768: .seealso: DMPlexGetCone()
2769: @*/
2770: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2771: {
2772:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


2780:   *equal = PETSC_FALSE;
2781:   DMPlexGetDepth(dmA, &depth);
2782:   DMPlexGetDepth(dmB, &depthB);
2783:   if (depth != depthB) return(0);
2784:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2785:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2786:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2787:   for (p = pStart; p < pEnd; ++p) {
2788:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2789:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

2791:     DMPlexGetConeSize(dmA, p, &coneSize);
2792:     DMPlexGetCone(dmA, p, &cone);
2793:     DMPlexGetConeOrientation(dmA, p, &ornt);
2794:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2795:     DMPlexGetCone(dmB, p, &coneB);
2796:     DMPlexGetConeOrientation(dmB, p, &orntB);
2797:     if (coneSize != coneSizeB) return(0);
2798:     for (c = 0; c < coneSize; ++c) {
2799:       if (cone[c] != coneB[c]) return(0);
2800:       if (ornt[c] != orntB[c]) return(0);
2801:     }
2802:     DMPlexGetSupportSize(dmA, p, &supportSize);
2803:     DMPlexGetSupport(dmA, p, &support);
2804:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2805:     DMPlexGetSupport(dmB, p, &supportB);
2806:     if (supportSize != supportSizeB) return(0);
2807:     for (s = 0; s < supportSize; ++s) {
2808:       if (support[s] != supportB[s]) return(0);
2809:     }
2810:   }
2811:   *equal = PETSC_TRUE;
2812:   return(0);
2813: }

2815: /*@C
2816:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

2818:   Not Collective

2820:   Input Parameters:
2821: + dm         - The DMPlex
2822: . cellDim    - The cell dimension
2823: - numCorners - The number of vertices on a cell

2825:   Output Parameters:
2826: . numFaceVertices - The number of vertices on a face

2828:   Level: developer

2830:   Notes:
2831:   Of course this can only work for a restricted set of symmetric shapes

2833: .seealso: DMPlexGetCone()
2834: @*/
2835: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2836: {
2837:   MPI_Comm       comm;

2841:   PetscObjectGetComm((PetscObject)dm,&comm);
2843:   switch (cellDim) {
2844:   case 0:
2845:     *numFaceVertices = 0;
2846:     break;
2847:   case 1:
2848:     *numFaceVertices = 1;
2849:     break;
2850:   case 2:
2851:     switch (numCorners) {
2852:     case 3: /* triangle */
2853:       *numFaceVertices = 2; /* Edge has 2 vertices */
2854:       break;
2855:     case 4: /* quadrilateral */
2856:       *numFaceVertices = 2; /* Edge has 2 vertices */
2857:       break;
2858:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2859:       *numFaceVertices = 3; /* Edge has 3 vertices */
2860:       break;
2861:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2862:       *numFaceVertices = 3; /* Edge has 3 vertices */
2863:       break;
2864:     default:
2865:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2866:     }
2867:     break;
2868:   case 3:
2869:     switch (numCorners) {
2870:     case 4: /* tetradehdron */
2871:       *numFaceVertices = 3; /* Face has 3 vertices */
2872:       break;
2873:     case 6: /* tet cohesive cells */
2874:       *numFaceVertices = 4; /* Face has 4 vertices */
2875:       break;
2876:     case 8: /* hexahedron */
2877:       *numFaceVertices = 4; /* Face has 4 vertices */
2878:       break;
2879:     case 9: /* tet cohesive Lagrange cells */
2880:       *numFaceVertices = 6; /* Face has 6 vertices */
2881:       break;
2882:     case 10: /* quadratic tetrahedron */
2883:       *numFaceVertices = 6; /* Face has 6 vertices */
2884:       break;
2885:     case 12: /* hex cohesive Lagrange cells */
2886:       *numFaceVertices = 6; /* Face has 6 vertices */
2887:       break;
2888:     case 18: /* quadratic tet cohesive Lagrange cells */
2889:       *numFaceVertices = 6; /* Face has 6 vertices */
2890:       break;
2891:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2892:       *numFaceVertices = 9; /* Face has 9 vertices */
2893:       break;
2894:     default:
2895:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2896:     }
2897:     break;
2898:   default:
2899:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
2900:   }
2901:   return(0);
2902: }

2904: /*@
2905:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

2907:   Not Collective

2909:   Input Parameter:
2910: . dm    - The DMPlex object

2912:   Output Parameter:
2913: . depthLabel - The DMLabel recording point depth

2915:   Level: developer

2917: .keywords: mesh, points
2918: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2919: @*/
2920: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2921: {

2927:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
2928:   *depthLabel = dm->depthLabel;
2929:   return(0);
2930: }

2932: /*@
2933:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

2935:   Not Collective

2937:   Input Parameter:
2938: . dm    - The DMPlex object

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

2943:   Level: developer

2945: .keywords: mesh, points
2946: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2947: @*/
2948: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
2949: {
2950:   DMLabel        label;
2951:   PetscInt       d = 0;

2957:   DMPlexGetDepthLabel(dm, &label);
2958:   if (label) {DMLabelGetNumValues(label, &d);}
2959:   *depth = d-1;
2960:   return(0);
2961: }

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

2966:   Not Collective

2968:   Input Parameters:
2969: + dm           - The DMPlex object
2970: - stratumValue - The requested depth

2972:   Output Parameters:
2973: + start - The first point at this depth
2974: - end   - One beyond the last point at this depth

2976:   Level: developer

2978: .keywords: mesh, points
2979: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
2980: @*/
2981: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2982: {
2983:   DMLabel        label;
2984:   PetscInt       pStart, pEnd;

2991:   DMPlexGetChart(dm, &pStart, &pEnd);
2992:   if (pStart == pEnd) return(0);
2993:   if (stratumValue < 0) {
2994:     if (start) *start = pStart;
2995:     if (end)   *end   = pEnd;
2996:     return(0);
2997:   }
2998:   DMPlexGetDepthLabel(dm, &label);
2999:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3000:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3001:   return(0);
3002: }

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

3007:   Not Collective

3009:   Input Parameters:
3010: + dm           - The DMPlex object
3011: - stratumValue - The requested height

3013:   Output Parameters:
3014: + start - The first point at this height
3015: - end   - One beyond the last point at this height

3017:   Level: developer

3019: .keywords: mesh, points
3020: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3021: @*/
3022: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3023: {
3024:   DMLabel        label;
3025:   PetscInt       depth, pStart, pEnd;

3032:   DMPlexGetChart(dm, &pStart, &pEnd);
3033:   if (pStart == pEnd) return(0);
3034:   if (stratumValue < 0) {
3035:     if (start) *start = pStart;
3036:     if (end)   *end   = pEnd;
3037:     return(0);
3038:   }
3039:   DMPlexGetDepthLabel(dm, &label);
3040:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3041:   DMLabelGetNumValues(label, &depth);
3042:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3043:   return(0);
3044: }

3046: /* Set the number of dof on each point and separate by fields */
3047: static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3048: {
3049:   PetscInt      *pMax;
3050:   PetscInt       depth, pStart = 0, pEnd = 0;
3051:   PetscInt       Nf, p, d, dep, f;
3052:   PetscBool     *isFE;

3056:   PetscMalloc1(numFields, &isFE);
3057:   DMGetNumFields(dm, &Nf);
3058:   for (f = 0; f < numFields; ++f) {
3059:     PetscObject  obj;
3060:     PetscClassId id;

3062:     isFE[f] = PETSC_FALSE;
3063:     if (f >= Nf) continue;
3064:     DMGetField(dm, f, &obj);
3065:     PetscObjectGetClassId(obj, &id);
3066:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
3067:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3068:   }
3069:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
3070:   if (numFields > 0) {
3071:     PetscSectionSetNumFields(*section, numFields);
3072:     if (numComp) {
3073:       for (f = 0; f < numFields; ++f) {
3074:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
3075:         if (isFE[f]) {
3076:           PetscFE           fe;
3077:           PetscDualSpace    dspace;
3078:           const PetscInt    ***perms;
3079:           const PetscScalar ***flips;
3080:           const PetscInt    *numDof;

3082:           DMGetField(dm,f,(PetscObject *) &fe);
3083:           PetscFEGetDualSpace(fe,&dspace);
3084:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3085:           PetscDualSpaceGetNumDof(dspace,&numDof);
3086:           if (perms || flips) {
3087:             DM               K;
3088:             DMLabel          depthLabel;
3089:             PetscInt         depth, h;
3090:             PetscSectionSym  sym;

3092:             PetscDualSpaceGetDM(dspace,&K);
3093:             DMPlexGetDepthLabel(dm,&depthLabel);
3094:             DMPlexGetDepth(dm,&depth);
3095:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
3096:             for (h = 0; h <= depth; h++) {
3097:               PetscDualSpace    hspace;
3098:               PetscInt          kStart, kEnd;
3099:               PetscInt          kConeSize;
3100:               const PetscInt    **perms0 = NULL;
3101:               const PetscScalar **flips0 = NULL;

3103:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
3104:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
3105:               if (!hspace) continue;
3106:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
3107:               if (perms) perms0 = perms[0];
3108:               if (flips) flips0 = flips[0];
3109:               if (!(perms0 || flips0)) continue;
3110:               DMPlexGetConeSize(K,kStart,&kConeSize);
3111:               PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
3112:             }
3113:             PetscSectionSetFieldSym(*section,f,sym);
3114:             PetscSectionSymDestroy(&sym);
3115:           }
3116:         }
3117:       }
3118:     }
3119:   }
3120:   DMPlexGetChart(dm, &pStart, &pEnd);
3121:   PetscSectionSetChart(*section, pStart, pEnd);
3122:   DMPlexGetDepth(dm, &depth);
3123:   PetscMalloc1(depth+1,&pMax);
3124:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3125:   for (dep = 0; dep <= depth; ++dep) {
3126:     d    = dim == depth ? dep : (!dep ? 0 : dim);
3127:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3128:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3129:     for (p = pStart; p < pEnd; ++p) {
3130:       PetscInt tot = 0;

3132:       for (f = 0; f < numFields; ++f) {
3133:         if (isFE[f] && p >= pMax[dep]) continue;
3134:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3135:         tot += numDof[f*(dim+1)+d];
3136:       }
3137:       PetscSectionSetDof(*section, p, tot);
3138:     }
3139:   }
3140:   PetscFree(pMax);
3141:   PetscFree(isFE);
3142:   return(0);
3143: }

3145: /* Set the number of dof on each point and separate by fields
3146:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3147: */
3148: static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3149: {
3150:   PetscInt       numFields;
3151:   PetscInt       bc;
3152:   PetscSection   aSec;

3156:   PetscSectionGetNumFields(section, &numFields);
3157:   for (bc = 0; bc < numBC; ++bc) {
3158:     PetscInt        field = 0;
3159:     const PetscInt *comp;
3160:     const PetscInt *idx;
3161:     PetscInt        Nc = -1, n, i;

3163:     if (numFields) field = bcField[bc];
3164:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3165:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3166:     ISGetLocalSize(bcPoints[bc], &n);
3167:     ISGetIndices(bcPoints[bc], &idx);
3168:     for (i = 0; i < n; ++i) {
3169:       const PetscInt p = idx[i];
3170:       PetscInt       numConst;

3172:       if (numFields) {
3173:         PetscSectionGetFieldDof(section, p, field, &numConst);
3174:       } else {
3175:         PetscSectionGetDof(section, p, &numConst);
3176:       }
3177:       /* If Nc < 0, constrain every dof on the point */
3178:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3179:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3180:       PetscSectionAddConstraintDof(section, p, numConst);
3181:     }
3182:     ISRestoreIndices(bcPoints[bc], &idx);
3183:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3184:   }
3185:   DMPlexGetAnchors(dm, &aSec, NULL);
3186:   if (aSec) {
3187:     PetscInt aStart, aEnd, a;

3189:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3190:     for (a = aStart; a < aEnd; a++) {
3191:       PetscInt dof, f;

3193:       PetscSectionGetDof(aSec, a, &dof);
3194:       if (dof) {
3195:         /* if there are point-to-point constraints, then all dofs are constrained */
3196:         PetscSectionGetDof(section, a, &dof);
3197:         PetscSectionSetConstraintDof(section, a, dof);
3198:         for (f = 0; f < numFields; f++) {
3199:           PetscSectionGetFieldDof(section, a, f, &dof);
3200:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3201:         }
3202:       }
3203:     }
3204:   }
3205:   return(0);
3206: }

3208: /* Set the constrained field indices on each point
3209:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3210: */
3211: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3212: {
3213:   PetscSection   aSec;
3214:   PetscInt      *indices;
3215:   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;

3219:   PetscSectionGetNumFields(section, &numFields);
3220:   if (!numFields) return(0);
3221:   /* Initialize all field indices to -1 */
3222:   PetscSectionGetChart(section, &pStart, &pEnd);
3223:   PetscSectionGetMaxDof(section, &maxDof);
3224:   PetscMalloc1(maxDof, &indices);
3225:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3226:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3227:   /* Handle BC constraints */
3228:   for (bc = 0; bc < numBC; ++bc) {
3229:     const PetscInt  field = bcField[bc];
3230:     const PetscInt *comp, *idx;
3231:     PetscInt        Nc = -1, n, i;

3233:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3234:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3235:     ISGetLocalSize(bcPoints[bc], &n);
3236:     ISGetIndices(bcPoints[bc], &idx);
3237:     for (i = 0; i < n; ++i) {
3238:       const PetscInt  p = idx[i];
3239:       const PetscInt *find;
3240:       PetscInt        fcdof, c;

3242:       PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3243:       if (Nc < 0) {
3244:         for (d = 0; d < fcdof; ++d) indices[d] = d;
3245:       } else {
3246:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3247:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3248:         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
3249:         PetscSortInt(d+Nc, indices);
3250:         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
3251:       }
3252:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3253:     }
3254:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3255:     ISRestoreIndices(bcPoints[bc], &idx);
3256:   }
3257:   /* Handle anchors */
3258:   DMPlexGetAnchors(dm, &aSec, NULL);
3259:   if (aSec) {
3260:     PetscInt aStart, aEnd, a;

3262:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3263:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3264:     for (a = aStart; a < aEnd; a++) {
3265:       PetscInt dof, fdof, f;

3267:       PetscSectionGetDof(aSec, a, &dof);
3268:       if (dof) {
3269:         /* if there are point-to-point constraints, then all dofs are constrained */
3270:         for (f = 0; f < numFields; f++) {
3271:           PetscSectionGetFieldDof(section, a, f, &fdof);
3272:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3273:         }
3274:       }
3275:     }
3276:   }
3277:   PetscFree(indices);
3278:   return(0);
3279: }

3281: /* Set the constrained indices on each point */
3282: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3283: {
3284:   PetscInt      *indices;
3285:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3289:   PetscSectionGetNumFields(section, &numFields);
3290:   PetscSectionGetMaxDof(section, &maxDof);
3291:   PetscSectionGetChart(section, &pStart, &pEnd);
3292:   PetscMalloc1(maxDof, &indices);
3293:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3294:   for (p = pStart; p < pEnd; ++p) {
3295:     PetscInt cdof, d;

3297:     PetscSectionGetConstraintDof(section, p, &cdof);
3298:     if (cdof) {
3299:       if (numFields) {
3300:         PetscInt numConst = 0, foff = 0;

3302:         for (f = 0; f < numFields; ++f) {
3303:           const PetscInt *find;
3304:           PetscInt        fcdof, fdof;

3306:           PetscSectionGetFieldDof(section, p, f, &fdof);
3307:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3308:           /* Change constraint numbering from field component to local dof number */
3309:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3310:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3311:           numConst += fcdof;
3312:           foff     += fdof;
3313:         }
3314:         if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
3315:       } else {
3316:         for (d = 0; d < cdof; ++d) indices[d] = d;
3317:       }
3318:       PetscSectionSetConstraintIndices(section, p, indices);
3319:     }
3320:   }
3321:   PetscFree(indices);
3322:   return(0);
3323: }

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

3328:   Not Collective

3330:   Input Parameters:
3331: + dm        - The DMPlex object
3332: . dim       - The spatial dimension of the problem
3333: . numFields - The number of fields in the problem
3334: . numComp   - An array of size numFields that holds the number of components for each field
3335: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3336: . numBC     - The number of boundary conditions
3337: . bcField   - An array of size numBC giving the field number for each boundry condition
3338: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3339: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3340: - perm      - Optional permutation of the chart, or NULL

3342:   Output Parameter:
3343: . section - The PetscSection object

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

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

3350:   Level: developer

3352:   Fortran Notes:
3353:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3355: .keywords: mesh, elements
3356: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3357: @*/
3358: 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)
3359: {
3360:   PetscSection   aSec;

3364:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3365:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3366:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3367:   PetscSectionSetUp(*section);
3368:   DMPlexGetAnchors(dm,&aSec,NULL);
3369:   if (numBC || aSec) {
3370:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3371:     DMPlexCreateSectionBCIndices(dm, *section);
3372:   }
3373:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3374:   return(0);
3375: }

3377: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3378: {
3379:   PetscSection   section, s;
3380:   Mat            m;
3381:   PetscInt       maxHeight;

3385:   DMClone(dm, cdm);
3386:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3387:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3388:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3389:   DMSetDefaultSection(*cdm, section);
3390:   PetscSectionDestroy(&section);
3391:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3392:   MatCreate(PETSC_COMM_SELF, &m);
3393:   DMSetDefaultConstraints(*cdm, s, m);
3394:   PetscSectionDestroy(&s);
3395:   MatDestroy(&m);
3396:   return(0);
3397: }

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

3402:   Not Collective

3404:   Input Parameters:
3405: . dm        - The DMPlex object

3407:   Output Parameter:
3408: . section - The PetscSection object

3410:   Level: developer

3412: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3413: @*/
3414: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3415: {
3416:   DM_Plex *mesh = (DM_Plex*) dm->data;

3420:   if (section) *section = mesh->coneSection;
3421:   return(0);
3422: }

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

3427:   Not Collective

3429:   Input Parameters:
3430: . dm        - The DMPlex object

3432:   Output Parameter:
3433: . section - The PetscSection object

3435:   Level: developer

3437: .seealso: DMPlexGetConeSection()
3438: @*/
3439: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3440: {
3441:   DM_Plex *mesh = (DM_Plex*) dm->data;

3445:   if (section) *section = mesh->supportSection;
3446:   return(0);
3447: }

3449: /*@C
3450:   DMPlexGetCones - Return cone data

3452:   Not Collective

3454:   Input Parameters:
3455: . dm        - The DMPlex object

3457:   Output Parameter:
3458: . cones - The cone for each point

3460:   Level: developer

3462: .seealso: DMPlexGetConeSection()
3463: @*/
3464: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3465: {
3466:   DM_Plex *mesh = (DM_Plex*) dm->data;

3470:   if (cones) *cones = mesh->cones;
3471:   return(0);
3472: }

3474: /*@C
3475:   DMPlexGetConeOrientations - Return cone orientation data

3477:   Not Collective

3479:   Input Parameters:
3480: . dm        - The DMPlex object

3482:   Output Parameter:
3483: . coneOrientations - The cone orientation for each point

3485:   Level: developer

3487: .seealso: DMPlexGetConeSection()
3488: @*/
3489: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3490: {
3491:   DM_Plex *mesh = (DM_Plex*) dm->data;

3495:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3496:   return(0);
3497: }

3499: /******************************** FEM Support **********************************/

3501: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section)
3502: {
3503:   PetscInt      *perm;
3504:   PetscInt       dim, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3508:   if (!section) {DMGetDefaultSection(dm, &section);}
3509:   DMGetDimension(dm, &dim);
3510:   PetscSectionGetNumFields(section, &Nf);
3511:   if (dim <= 1) return(0);
3512:   for (f = 0; f < Nf; ++f) {
3513:     /* An order k SEM disc has k-1 dofs on an edge */
3514:     DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3515:     PetscSectionGetFieldDof(section, eStart, f, &k);
3516:     PetscSectionGetFieldComponents(section, f, &Nc);
3517:     k = k/Nc + 1;
3518:     size += PetscPowInt(k+1, dim)*Nc;
3519:   }
3520:   PetscMalloc1(size, &perm);
3521:   for (f = 0; f < Nf; ++f) {
3522:     switch (dim) {
3523:     case 2:
3524:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3525:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3526:       PetscSectionGetFieldDof(section, eStart, f, &k);
3527:       PetscSectionGetFieldComponents(section, f, &Nc);
3528:       k = k/Nc + 1;
3529:       /* The SEM order is

3531:          v_lb, {e_b}, v_rb,
3532:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3533:          v_lt, reverse {e_t}, v_rt
3534:       */
3535:       {
3536:         const PetscInt of   = 0;
3537:         const PetscInt oeb  = of   + PetscSqr(k-1);
3538:         const PetscInt oer  = oeb  + (k-1);
3539:         const PetscInt oet  = oer  + (k-1);
3540:         const PetscInt oel  = oet  + (k-1);
3541:         const PetscInt ovlb = oel  + (k-1);
3542:         const PetscInt ovrb = ovlb + 1;
3543:         const PetscInt ovrt = ovrb + 1;
3544:         const PetscInt ovlt = ovrt + 1;
3545:         PetscInt       o;

3547:         /* bottom */
3548:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3549:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3550:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3551:         /* middle */
3552:         for (i = 0; i < k-1; ++i) {
3553:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3554:           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;
3555:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3556:         }
3557:         /* top */
3558:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3559:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3560:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3561:         foffset = offset;
3562:       }
3563:       break;
3564:     case 3:
3565:       /* The original hex closure is

3567:          {c,
3568:           f_b, f_t, f_f, f_b, f_r, f_l,
3569:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3570:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3571:       */
3572:       DMPlexGetDepthStratum(dm, 1, &eStart, NULL);
3573:       PetscSectionGetFieldDof(section, eStart, f, &k);
3574:       PetscSectionGetFieldComponents(section, f, &Nc);
3575:       k = k/Nc + 1;
3576:       /* The SEM order is
3577:          Bottom Slice
3578:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3579:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3580:          v_blb, {e_bb}, v_brb,

3582:          Middle Slice (j)
3583:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3584:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3585:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3587:          Top Slice
3588:          v_tlf, {e_tf}, v_trf,
3589:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3590:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3591:       */
3592:       {
3593:         const PetscInt oc    = 0;
3594:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3595:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3596:         const PetscInt off   = oft   + PetscSqr(k-1);
3597:         const PetscInt ofk   = off   + PetscSqr(k-1);
3598:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3599:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3600:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3601:         const PetscInt oebb  = oebl  + (k-1);
3602:         const PetscInt oebr  = oebb  + (k-1);
3603:         const PetscInt oebf  = oebr  + (k-1);
3604:         const PetscInt oetf  = oebf  + (k-1);
3605:         const PetscInt oetr  = oetf  + (k-1);
3606:         const PetscInt oetb  = oetr  + (k-1);
3607:         const PetscInt oetl  = oetb  + (k-1);
3608:         const PetscInt oerf  = oetl  + (k-1);
3609:         const PetscInt oelf  = oerf  + (k-1);
3610:         const PetscInt oelb  = oelf  + (k-1);
3611:         const PetscInt oerb  = oelb  + (k-1);
3612:         const PetscInt ovblf = oerb  + (k-1);
3613:         const PetscInt ovblb = ovblf + 1;
3614:         const PetscInt ovbrb = ovblb + 1;
3615:         const PetscInt ovbrf = ovbrb + 1;
3616:         const PetscInt ovtlf = ovbrf + 1;
3617:         const PetscInt ovtrf = ovtlf + 1;
3618:         const PetscInt ovtrb = ovtrf + 1;
3619:         const PetscInt ovtlb = ovtrb + 1;
3620:         PetscInt       o, n;

3622:         /* Bottom Slice */
3623:         /*   bottom */
3624:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3625:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3626:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3627:         /*   middle */
3628:         for (i = 0; i < k-1; ++i) {
3629:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3630:           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;}
3631:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3632:         }
3633:         /*   top */
3634:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3635:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3636:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3638:         /* Middle Slice */
3639:         for (j = 0; j < k-1; ++j) {
3640:           /*   bottom */
3641:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3642:           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;
3643:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3644:           /*   middle */
3645:           for (i = 0; i < k-1; ++i) {
3646:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3647:             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;
3648:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3649:           }
3650:           /*   top */
3651:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3652:           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;
3653:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3654:         }

3656:         /* Top Slice */
3657:         /*   bottom */
3658:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3659:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3660:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3661:         /*   middle */
3662:         for (i = 0; i < k-1; ++i) {
3663:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3664:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3665:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3666:         }
3667:         /*   top */
3668:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3669:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3670:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3672:         foffset = offset;
3673:       }
3674:       break;
3675:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3676:     }
3677:   }
3678:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3679:   /* Check permutation */
3680:   {
3681:     PetscInt *check;

3683:     PetscMalloc1(size, &check);
3684:     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]);}
3685:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3686:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3687:     PetscFree(check);
3688:   }
3689:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3690:   return(0);
3691: }

3693: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3694: {
3695:   PetscDS        prob;
3696:   PetscInt       depth, Nf, h;
3697:   DMLabel        label;

3701:   prob    = dm->prob;
3702:   Nf      = prob->Nf;
3703:   label   = dm->depthLabel;
3704:   *dspace = NULL;
3705:   if (field < Nf) {
3706:     PetscObject disc = prob->disc[field];

3708:     if (disc->classid == PETSCFE_CLASSID) {
3709:       PetscDualSpace dsp;

3711:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3712:       DMLabelGetNumValues(label,&depth);
3713:       DMLabelGetValue(label,point,&h);
3714:       h    = depth - 1 - h;
3715:       if (h) {
3716:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3717:       } else {
3718:         *dspace = dsp;
3719:       }
3720:     }
3721:   }
3722:   return(0);
3723: }


3726: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3727: {
3728:   PetscScalar    *array, *vArray;
3729:   const PetscInt *cone, *coneO;
3730:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3731:   PetscErrorCode  ierr;

3734:   PetscSectionGetChart(section, &pStart, &pEnd);
3735:   DMPlexGetConeSize(dm, point, &numPoints);
3736:   DMPlexGetCone(dm, point, &cone);
3737:   DMPlexGetConeOrientation(dm, point, &coneO);
3738:   if (!values || !*values) {
3739:     if ((point >= pStart) && (point < pEnd)) {
3740:       PetscInt dof;

3742:       PetscSectionGetDof(section, point, &dof);
3743:       size += dof;
3744:     }
3745:     for (p = 0; p < numPoints; ++p) {
3746:       const PetscInt cp = cone[p];
3747:       PetscInt       dof;

3749:       if ((cp < pStart) || (cp >= pEnd)) continue;
3750:       PetscSectionGetDof(section, cp, &dof);
3751:       size += dof;
3752:     }
3753:     if (!values) {
3754:       if (csize) *csize = size;
3755:       return(0);
3756:     }
3757:     DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
3758:   } else {
3759:     array = *values;
3760:   }
3761:   size = 0;
3762:   VecGetArray(v, &vArray);
3763:   if ((point >= pStart) && (point < pEnd)) {
3764:     PetscInt     dof, off, d;
3765:     PetscScalar *varr;

3767:     PetscSectionGetDof(section, point, &dof);
3768:     PetscSectionGetOffset(section, point, &off);
3769:     varr = &vArray[off];
3770:     for (d = 0; d < dof; ++d, ++offset) {
3771:       array[offset] = varr[d];
3772:     }
3773:     size += dof;
3774:   }
3775:   for (p = 0; p < numPoints; ++p) {
3776:     const PetscInt cp = cone[p];
3777:     PetscInt       o  = coneO[p];
3778:     PetscInt       dof, off, d;
3779:     PetscScalar   *varr;

3781:     if ((cp < pStart) || (cp >= pEnd)) continue;
3782:     PetscSectionGetDof(section, cp, &dof);
3783:     PetscSectionGetOffset(section, cp, &off);
3784:     varr = &vArray[off];
3785:     if (o >= 0) {
3786:       for (d = 0; d < dof; ++d, ++offset) {
3787:         array[offset] = varr[d];
3788:       }
3789:     } else {
3790:       for (d = dof-1; d >= 0; --d, ++offset) {
3791:         array[offset] = varr[d];
3792:       }
3793:     }
3794:     size += dof;
3795:   }
3796:   VecRestoreArray(v, &vArray);
3797:   if (!*values) {
3798:     if (csize) *csize = size;
3799:     *values = array;
3800:   } else {
3801:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3802:     *csize = size;
3803:   }
3804:   return(0);
3805: }

3807: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3808: {
3809:   const PetscInt *cla;
3810:   PetscInt       np, *pts = NULL;

3814:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3815:   if (!*clPoints) {
3816:     PetscInt pStart, pEnd, p, q;

3818:     PetscSectionGetChart(section, &pStart, &pEnd);
3819:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3820:     /* Compress out points not in the section */
3821:     for (p = 0, q = 0; p < np; p++) {
3822:       PetscInt r = pts[2*p];
3823:       if ((r >= pStart) && (r < pEnd)) {
3824:         pts[q*2]   = r;
3825:         pts[q*2+1] = pts[2*p+1];
3826:         ++q;
3827:       }
3828:     }
3829:     np = q;
3830:     cla = NULL;
3831:   } else {
3832:     PetscInt dof, off;

3834:     PetscSectionGetDof(*clSec, point, &dof);
3835:     PetscSectionGetOffset(*clSec, point, &off);
3836:     ISGetIndices(*clPoints, &cla);
3837:     np   = dof/2;
3838:     pts  = (PetscInt *) &cla[off];
3839:   }
3840:   *numPoints = np;
3841:   *points    = pts;
3842:   *clp       = cla;

3844:   return(0);
3845: }

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

3852:   if (!*clPoints) {
3853:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3854:   } else {
3855:     ISRestoreIndices(*clPoints, clp);
3856:   }
3857:   *numPoints = 0;
3858:   *points    = NULL;
3859:   *clSec     = NULL;
3860:   *clPoints  = NULL;
3861:   *clp       = NULL;
3862:   return(0);
3863: }

3865: 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[])
3866: {
3867:   PetscInt          offset = 0, p;
3868:   const PetscInt    **perms = NULL;
3869:   const PetscScalar **flips = NULL;
3870:   PetscErrorCode    ierr;

3873:   *size = 0;
3874:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3875:   for (p = 0; p < numPoints; p++) {
3876:     const PetscInt    point = points[2*p];
3877:     const PetscInt    *perm = perms ? perms[p] : NULL;
3878:     const PetscScalar *flip = flips ? flips[p] : NULL;
3879:     PetscInt          dof, off, d;
3880:     const PetscScalar *varr;

3882:     PetscSectionGetDof(section, point, &dof);
3883:     PetscSectionGetOffset(section, point, &off);
3884:     varr = &vArray[off];
3885:     if (clperm) {
3886:       if (perm) {
3887:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3888:       } else {
3889:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
3890:       }
3891:       if (flip) {
3892:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
3893:       }
3894:     } else {
3895:       if (perm) {
3896:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
3897:       } else {
3898:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
3899:       }
3900:       if (flip) {
3901:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
3902:       }
3903:     }
3904:     offset += dof;
3905:   }
3906:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3907:   *size = offset;
3908:   return(0);
3909: }

3911: 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[])
3912: {
3913:   PetscInt          offset = 0, f;
3914:   PetscErrorCode    ierr;

3917:   *size = 0;
3918:   for (f = 0; f < numFields; ++f) {
3919:     PetscInt          p;
3920:     const PetscInt    **perms = NULL;
3921:     const PetscScalar **flips = NULL;

3923:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3924:     for (p = 0; p < numPoints; p++) {
3925:       const PetscInt    point = points[2*p];
3926:       PetscInt          fdof, foff, b;
3927:       const PetscScalar *varr;
3928:       const PetscInt    *perm = perms ? perms[p] : NULL;
3929:       const PetscScalar *flip = flips ? flips[p] : NULL;

3931:       PetscSectionGetFieldDof(section, point, f, &fdof);
3932:       PetscSectionGetFieldOffset(section, point, f, &foff);
3933:       varr = &vArray[foff];
3934:       if (clperm) {
3935:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
3936:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
3937:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
3938:       } else {
3939:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
3940:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
3941:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
3942:       }
3943:       offset += fdof;
3944:     }
3945:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3946:   }
3947:   *size = offset;
3948:   return(0);
3949: }

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

3954:   Not collective

3956:   Input Parameters:
3957: + dm - The DM
3958: . section - The section describing the layout in v, or NULL to use the default section
3959: . v - The local vector
3960: - point - The sieve point in the DM

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

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

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

3972:   Level: intermediate

3974: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3975: @*/
3976: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3977: {
3978:   PetscSection       clSection;
3979:   IS                 clPoints;
3980:   PetscScalar       *array;
3981:   const PetscScalar *vArray;
3982:   PetscInt          *points = NULL;
3983:   const PetscInt    *clp, *perm;
3984:   PetscInt           depth, numFields, numPoints, size;
3985:   PetscErrorCode     ierr;

3989:   if (!section) {DMGetDefaultSection(dm, &section);}
3992:   DMPlexGetDepth(dm, &depth);
3993:   PetscSectionGetNumFields(section, &numFields);
3994:   if (depth == 1 && numFields < 2) {
3995:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
3996:     return(0);
3997:   }
3998:   /* Get points */
3999:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4000:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4001:   /* Get array */
4002:   if (!values || !*values) {
4003:     PetscInt asize = 0, dof, p;

4005:     for (p = 0; p < numPoints*2; p += 2) {
4006:       PetscSectionGetDof(section, points[p], &dof);
4007:       asize += dof;
4008:     }
4009:     if (!values) {
4010:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4011:       if (csize) *csize = asize;
4012:       return(0);
4013:     }
4014:     DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
4015:   } else {
4016:     array = *values;
4017:   }
4018:   VecGetArrayRead(v, &vArray);
4019:   /* Get values */
4020:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4021:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4022:   /* Cleanup points */
4023:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4024:   /* Cleanup array */
4025:   VecRestoreArrayRead(v, &vArray);
4026:   if (!*values) {
4027:     if (csize) *csize = size;
4028:     *values = array;
4029:   } else {
4030:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4031:     *csize = size;
4032:   }
4033:   return(0);
4034: }

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

4039:   Not collective

4041:   Input Parameters:
4042: + dm - The DM
4043: . section - The section describing the layout in v, or NULL to use the default section
4044: . v - The local vector
4045: . point - The sieve point in the DM
4046: . csize - The number of values in the closure, or NULL
4047: - values - The array of values, which is a borrowed array and should not be freed

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

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

4055:   Level: intermediate

4057: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4058: @*/
4059: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4060: {
4061:   PetscInt       size = 0;

4065:   /* Should work without recalculating size */
4066:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
4067:   return(0);
4068: }

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

4073: 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[])
4074: {
4075:   PetscInt        cdof;   /* The number of constraints on this point */
4076:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4077:   PetscScalar    *a;
4078:   PetscInt        off, cind = 0, k;
4079:   PetscErrorCode  ierr;

4082:   PetscSectionGetConstraintDof(section, point, &cdof);
4083:   PetscSectionGetOffset(section, point, &off);
4084:   a    = &array[off];
4085:   if (!cdof || setBC) {
4086:     if (clperm) {
4087:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4088:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4089:     } else {
4090:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4091:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4092:     }
4093:   } else {
4094:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4095:     if (clperm) {
4096:       if (perm) {for (k = 0; k < dof; ++k) {
4097:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4098:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4099:         }
4100:       } else {
4101:         for (k = 0; k < dof; ++k) {
4102:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4103:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4104:         }
4105:       }
4106:     } else {
4107:       if (perm) {
4108:         for (k = 0; k < dof; ++k) {
4109:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4110:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4111:         }
4112:       } else {
4113:         for (k = 0; k < dof; ++k) {
4114:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4115:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4116:         }
4117:       }
4118:     }
4119:   }
4120:   return(0);
4121: }

4123: 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[])
4124: {
4125:   PetscInt        cdof;   /* The number of constraints on this point */
4126:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4127:   PetscScalar    *a;
4128:   PetscInt        off, cind = 0, k;
4129:   PetscErrorCode  ierr;

4132:   PetscSectionGetConstraintDof(section, point, &cdof);
4133:   PetscSectionGetOffset(section, point, &off);
4134:   a    = &array[off];
4135:   if (cdof) {
4136:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4137:     if (clperm) {
4138:       if (perm) {
4139:         for (k = 0; k < dof; ++k) {
4140:           if ((cind < cdof) && (k == cdofs[cind])) {
4141:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4142:             cind++;
4143:           }
4144:         }
4145:       } else {
4146:         for (k = 0; k < dof; ++k) {
4147:           if ((cind < cdof) && (k == cdofs[cind])) {
4148:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4149:             cind++;
4150:           }
4151:         }
4152:       }
4153:     } else {
4154:       if (perm) {
4155:         for (k = 0; k < dof; ++k) {
4156:           if ((cind < cdof) && (k == cdofs[cind])) {
4157:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4158:             cind++;
4159:           }
4160:         }
4161:       } else {
4162:         for (k = 0; k < dof; ++k) {
4163:           if ((cind < cdof) && (k == cdofs[cind])) {
4164:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4165:             cind++;
4166:           }
4167:         }
4168:       }
4169:     }
4170:   }
4171:   return(0);
4172: }

4174: 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[])
4175: {
4176:   PetscScalar    *a;
4177:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4178:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4179:   PetscInt        cind = 0, b;
4180:   PetscErrorCode  ierr;

4183:   PetscSectionGetFieldDof(section, point, f, &fdof);
4184:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4185:   PetscSectionGetFieldOffset(section, point, f, &foff);
4186:   a    = &array[foff];
4187:   if (!fcdof || setBC) {
4188:     if (clperm) {
4189:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4190:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4191:     } else {
4192:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4193:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4194:     }
4195:   } else {
4196:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4197:     if (clperm) {
4198:       if (perm) {
4199:         for (b = 0; b < fdof; b++) {
4200:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4201:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4202:         }
4203:       } else {
4204:         for (b = 0; b < fdof; b++) {
4205:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4206:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4207:         }
4208:       }
4209:     } else {
4210:       if (perm) {
4211:         for (b = 0; b < fdof; b++) {
4212:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4213:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4214:         }
4215:       } else {
4216:         for (b = 0; b < fdof; b++) {
4217:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4218:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4219:         }
4220:       }
4221:     }
4222:   }
4223:   *offset += fdof;
4224:   return(0);
4225: }

4227: 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[])
4228: {
4229:   PetscScalar    *a;
4230:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4231:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4232:   PetscInt        cind = 0, b;
4233:   PetscErrorCode  ierr;

4236:   PetscSectionGetFieldDof(section, point, f, &fdof);
4237:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4238:   PetscSectionGetFieldOffset(section, point, f, &foff);
4239:   a    = &array[foff];
4240:   if (fcdof) {
4241:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4242:     if (clperm) {
4243:       if (perm) {
4244:         for (b = 0; b < fdof; b++) {
4245:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4246:             fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4247:             ++cind;
4248:           }
4249:         }
4250:       } else {
4251:         for (b = 0; b < fdof; b++) {
4252:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4253:             fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4254:             ++cind;
4255:           }
4256:         }
4257:       }
4258:     } else {
4259:       if (perm) {
4260:         for (b = 0; b < fdof; b++) {
4261:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4262:             fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4263:             ++cind;
4264:           }
4265:         }
4266:       } else {
4267:         for (b = 0; b < fdof; b++) {
4268:           if ((cind < fcdof) && (b == fcdofs[cind])) {
4269:             fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4270:             ++cind;
4271:           }
4272:         }
4273:       }
4274:     }
4275:   }
4276:   *offset += fdof;
4277:   return(0);
4278: }

4280: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4281: {
4282:   PetscScalar    *array;
4283:   const PetscInt *cone, *coneO;
4284:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4285:   PetscErrorCode  ierr;

4288:   PetscSectionGetChart(section, &pStart, &pEnd);
4289:   DMPlexGetConeSize(dm, point, &numPoints);
4290:   DMPlexGetCone(dm, point, &cone);
4291:   DMPlexGetConeOrientation(dm, point, &coneO);
4292:   VecGetArray(v, &array);
4293:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4294:     const PetscInt cp = !p ? point : cone[p-1];
4295:     const PetscInt o  = !p ? 0     : coneO[p-1];

4297:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4298:     PetscSectionGetDof(section, cp, &dof);
4299:     /* ADD_VALUES */
4300:     {
4301:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4302:       PetscScalar    *a;
4303:       PetscInt        cdof, coff, cind = 0, k;

4305:       PetscSectionGetConstraintDof(section, cp, &cdof);
4306:       PetscSectionGetOffset(section, cp, &coff);
4307:       a    = &array[coff];
4308:       if (!cdof) {
4309:         if (o >= 0) {
4310:           for (k = 0; k < dof; ++k) {
4311:             a[k] += values[off+k];
4312:           }
4313:         } else {
4314:           for (k = 0; k < dof; ++k) {
4315:             a[k] += values[off+dof-k-1];
4316:           }
4317:         }
4318:       } else {
4319:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4320:         if (o >= 0) {
4321:           for (k = 0; k < dof; ++k) {
4322:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4323:             a[k] += values[off+k];
4324:           }
4325:         } else {
4326:           for (k = 0; k < dof; ++k) {
4327:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4328:             a[k] += values[off+dof-k-1];
4329:           }
4330:         }
4331:       }
4332:     }
4333:   }
4334:   VecRestoreArray(v, &array);
4335:   return(0);
4336: }

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

4341:   Not collective

4343:   Input Parameters:
4344: + dm - The DM
4345: . section - The section describing the layout in v, or NULL to use the default section
4346: . v - The local vector
4347: . point - The sieve point in the DM
4348: . values - The array of values
4349: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

4354:   Level: intermediate

4356: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4357: @*/
4358: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4359: {
4360:   PetscSection    clSection;
4361:   IS              clPoints;
4362:   PetscScalar    *array;
4363:   PetscInt       *points = NULL;
4364:   const PetscInt *clp, *clperm;
4365:   PetscInt        depth, numFields, numPoints, p;
4366:   PetscErrorCode  ierr;

4370:   if (!section) {DMGetDefaultSection(dm, &section);}
4373:   DMPlexGetDepth(dm, &depth);
4374:   PetscSectionGetNumFields(section, &numFields);
4375:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4376:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4377:     return(0);
4378:   }
4379:   /* Get points */
4380:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4381:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4382:   /* Get array */
4383:   VecGetArray(v, &array);
4384:   /* Get values */
4385:   if (numFields > 0) {
4386:     PetscInt offset = 0, f;
4387:     for (f = 0; f < numFields; ++f) {
4388:       const PetscInt    **perms = NULL;
4389:       const PetscScalar **flips = NULL;

4391:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4392:       switch (mode) {
4393:       case INSERT_VALUES:
4394:         for (p = 0; p < numPoints; p++) {
4395:           const PetscInt    point = points[2*p];
4396:           const PetscInt    *perm = perms ? perms[p] : NULL;
4397:           const PetscScalar *flip = flips ? flips[p] : NULL;
4398:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4399:         } break;
4400:       case INSERT_ALL_VALUES:
4401:         for (p = 0; p < numPoints; p++) {
4402:           const PetscInt    point = points[2*p];
4403:           const PetscInt    *perm = perms ? perms[p] : NULL;
4404:           const PetscScalar *flip = flips ? flips[p] : NULL;
4405:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4406:         } break;
4407:       case INSERT_BC_VALUES:
4408:         for (p = 0; p < numPoints; p++) {
4409:           const PetscInt    point = points[2*p];
4410:           const PetscInt    *perm = perms ? perms[p] : NULL;
4411:           const PetscScalar *flip = flips ? flips[p] : NULL;
4412:           updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4413:         } break;
4414:       case ADD_VALUES:
4415:         for (p = 0; p < numPoints; p++) {
4416:           const PetscInt    point = points[2*p];
4417:           const PetscInt    *perm = perms ? perms[p] : NULL;
4418:           const PetscScalar *flip = flips ? flips[p] : NULL;
4419:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4420:         } break;
4421:       case ADD_ALL_VALUES:
4422:         for (p = 0; p < numPoints; p++) {
4423:           const PetscInt    point = points[2*p];
4424:           const PetscInt    *perm = perms ? perms[p] : NULL;
4425:           const PetscScalar *flip = flips ? flips[p] : NULL;
4426:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4427:         } break;
4428:       case ADD_BC_VALUES:
4429:         for (p = 0; p < numPoints; p++) {
4430:           const PetscInt    point = points[2*p];
4431:           const PetscInt    *perm = perms ? perms[p] : NULL;
4432:           const PetscScalar *flip = flips ? flips[p] : NULL;
4433:           updatePointFieldsBC_private(section, point, perm, flip, f, add, clperm, values, &offset, array);
4434:         } break;
4435:       default:
4436:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4437:       }
4438:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4439:     }
4440:   } else {
4441:     PetscInt dof, off;
4442:     const PetscInt    **perms = NULL;
4443:     const PetscScalar **flips = NULL;

4445:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4446:     switch (mode) {
4447:     case INSERT_VALUES:
4448:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4449:         const PetscInt    point = points[2*p];
4450:         const PetscInt    *perm = perms ? perms[p] : NULL;
4451:         const PetscScalar *flip = flips ? flips[p] : NULL;
4452:         PetscSectionGetDof(section, point, &dof);
4453:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4454:       } break;
4455:     case INSERT_ALL_VALUES:
4456:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4457:         const PetscInt    point = points[2*p];
4458:         const PetscInt    *perm = perms ? perms[p] : NULL;
4459:         const PetscScalar *flip = flips ? flips[p] : NULL;
4460:         PetscSectionGetDof(section, point, &dof);
4461:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4462:       } break;
4463:     case INSERT_BC_VALUES:
4464:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4465:         const PetscInt    point = points[2*p];
4466:         const PetscInt    *perm = perms ? perms[p] : NULL;
4467:         const PetscScalar *flip = flips ? flips[p] : NULL;
4468:         PetscSectionGetDof(section, point, &dof);
4469:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4470:       } break;
4471:     case ADD_VALUES:
4472:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4473:         const PetscInt    point = points[2*p];
4474:         const PetscInt    *perm = perms ? perms[p] : NULL;
4475:         const PetscScalar *flip = flips ? flips[p] : NULL;
4476:         PetscSectionGetDof(section, point, &dof);
4477:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4478:       } break;
4479:     case ADD_ALL_VALUES:
4480:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4481:         const PetscInt    point = points[2*p];
4482:         const PetscInt    *perm = perms ? perms[p] : NULL;
4483:         const PetscScalar *flip = flips ? flips[p] : NULL;
4484:         PetscSectionGetDof(section, point, &dof);
4485:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4486:       } break;
4487:     case ADD_BC_VALUES:
4488:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4489:         const PetscInt    point = points[2*p];
4490:         const PetscInt    *perm = perms ? perms[p] : NULL;
4491:         const PetscScalar *flip = flips ? flips[p] : NULL;
4492:         PetscSectionGetDof(section, point, &dof);
4493:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4494:       } break;
4495:     default:
4496:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4497:     }
4498:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4499:   }
4500:   /* Cleanup points */
4501:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4502:   /* Cleanup array */
4503:   VecRestoreArray(v, &array);
4504:   return(0);
4505: }

4507: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
4508: {
4509:   PetscSection      clSection;
4510:   IS                clPoints;
4511:   PetscScalar       *array;
4512:   PetscInt          *points = NULL;
4513:   const PetscInt    *clp, *clperm;
4514:   PetscInt          numFields, numPoints, p;
4515:   PetscInt          offset = 0, f;
4516:   PetscErrorCode    ierr;

4520:   if (!section) {DMGetDefaultSection(dm, &section);}
4523:   PetscSectionGetNumFields(section, &numFields);
4524:   /* Get points */
4525:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4526:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4527:   /* Get array */
4528:   VecGetArray(v, &array);
4529:   /* Get values */
4530:   for (f = 0; f < numFields; ++f) {
4531:     const PetscInt    **perms = NULL;
4532:     const PetscScalar **flips = NULL;

4534:     if (!fieldActive[f]) {
4535:       for (p = 0; p < numPoints*2; p += 2) {
4536:         PetscInt fdof;
4537:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4538:         offset += fdof;
4539:       }
4540:       continue;
4541:     }
4542:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4543:     switch (mode) {
4544:     case INSERT_VALUES:
4545:       for (p = 0; p < numPoints; p++) {
4546:         const PetscInt    point = points[2*p];
4547:         const PetscInt    *perm = perms ? perms[p] : NULL;
4548:         const PetscScalar *flip = flips ? flips[p] : NULL;
4549:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4550:       } break;
4551:     case INSERT_ALL_VALUES:
4552:       for (p = 0; p < numPoints; p++) {
4553:         const PetscInt    point = points[2*p];
4554:         const PetscInt    *perm = perms ? perms[p] : NULL;
4555:         const PetscScalar *flip = flips ? flips[p] : NULL;
4556:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4557:         } break;
4558:     case INSERT_BC_VALUES:
4559:       for (p = 0; p < numPoints; p++) {
4560:         const PetscInt    point = points[2*p];
4561:         const PetscInt    *perm = perms ? perms[p] : NULL;
4562:         const PetscScalar *flip = flips ? flips[p] : NULL;
4563:         updatePointFieldsBC_private(section, point, perm, flip, f, insert, clperm, values, &offset, array);
4564:       } break;
4565:     case ADD_VALUES:
4566:       for (p = 0; p < numPoints; p++) {
4567:         const PetscInt    point = points[2*p];
4568:         const PetscInt    *perm = perms ? perms[p] : NULL;
4569:         const PetscScalar *flip = flips ? flips[p] : NULL;
4570:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4571:       } break;
4572:     case ADD_ALL_VALUES:
4573:       for (p = 0; p < numPoints; p++) {
4574:         const PetscInt    point = points[2*p];
4575:         const PetscInt    *perm = perms ? perms[p] : NULL;
4576:         const PetscScalar *flip = flips ? flips[p] : NULL;
4577:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4578:       } break;
4579:     default:
4580:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4581:     }
4582:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4583:   }
4584:   /* Cleanup points */
4585:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4586:   /* Cleanup array */
4587:   VecRestoreArray(v, &array);
4588:   return(0);
4589: }

4591: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4592: {
4593:   PetscMPIInt    rank;
4594:   PetscInt       i, j;

4598:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4599:   PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);
4600:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4601:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4602:   numCIndices = numCIndices ? numCIndices : numRIndices;
4603:   for (i = 0; i < numRIndices; i++) {
4604:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4605:     for (j = 0; j < numCIndices; j++) {
4606: #if defined(PETSC_USE_COMPLEX)
4607:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4608: #else
4609:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4610: #endif
4611:     }
4612:     PetscViewerASCIIPrintf(viewer, "\n");
4613:   }
4614:   return(0);
4615: }

4617: /* . off - The global offset of this point */
4618: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4619: {
4620:   PetscInt        dof;    /* The number of unknowns on this point */
4621:   PetscInt        cdof;   /* The number of constraints on this point */
4622:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4623:   PetscInt        cind = 0, k;
4624:   PetscErrorCode  ierr;

4627:   PetscSectionGetDof(section, point, &dof);
4628:   PetscSectionGetConstraintDof(section, point, &cdof);
4629:   if (!cdof || setBC) {
4630:     if (perm) {
4631:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4632:     } else {
4633:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4634:     }
4635:   } else {
4636:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4637:     if (perm) {
4638:       for (k = 0; k < dof; ++k) {
4639:         if ((cind < cdof) && (k == cdofs[cind])) {
4640:           /* Insert check for returning constrained indices */
4641:           indices[*loff+perm[k]] = -(off+k+1);
4642:           ++cind;
4643:         } else {
4644:           indices[*loff+perm[k]] = off+k-cind;
4645:         }
4646:       }
4647:     } else {
4648:       for (k = 0; k < dof; ++k) {
4649:         if ((cind < cdof) && (k == cdofs[cind])) {
4650:           /* Insert check for returning constrained indices */
4651:           indices[*loff+k] = -(off+k+1);
4652:           ++cind;
4653:         } else {
4654:           indices[*loff+k] = off+k-cind;
4655:         }
4656:       }
4657:     }
4658:   }
4659:   *loff += dof;
4660:   return(0);
4661: }

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

4670:   PetscSectionGetNumFields(section, &numFields);
4671:   for (f = 0, foff = 0; f < numFields; ++f) {
4672:     PetscInt        fdof, cfdof;
4673:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4674:     PetscInt        cind = 0, b;
4675:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4677:     PetscSectionGetFieldDof(section, point, f, &fdof);
4678:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4679:     if (!cfdof || setBC) {
4680:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4681:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4682:     } else {
4683:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4684:       if (perm) {
4685:         for (b = 0; b < fdof; b++) {
4686:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4687:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4688:             ++cind;
4689:           } else {
4690:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4691:           }
4692:         }
4693:       } else {
4694:         for (b = 0; b < fdof; b++) {
4695:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4696:             indices[foffs[f]+b] = -(off+foff+b+1);
4697:             ++cind;
4698:           } else {
4699:             indices[foffs[f]+b] = off+foff+b-cind;
4700:           }
4701:         }
4702:       }
4703:     }
4704:     foff     += (setBC ? fdof : (fdof - cfdof));
4705:     foffs[f] += fdof;
4706:   }
4707:   return(0);
4708: }

4710: 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)
4711: {
4712:   Mat             cMat;
4713:   PetscSection    aSec, cSec;
4714:   IS              aIS;
4715:   PetscInt        aStart = -1, aEnd = -1;
4716:   const PetscInt  *anchors;
4717:   PetscInt        numFields, f, p, q, newP = 0;
4718:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4719:   PetscInt        *newPoints, *indices, *newIndices;
4720:   PetscInt        maxAnchor, maxDof;
4721:   PetscInt        newOffsets[32];
4722:   PetscInt        *pointMatOffsets[32];
4723:   PetscInt        *newPointOffsets[32];
4724:   PetscScalar     *pointMat[32];
4725:   PetscScalar     *newValues=NULL,*tmpValues;
4726:   PetscBool       anyConstrained = PETSC_FALSE;
4727:   PetscErrorCode  ierr;

4732:   PetscSectionGetNumFields(section, &numFields);

4734:   DMPlexGetAnchors(dm,&aSec,&aIS);
4735:   /* if there are point-to-point constraints */
4736:   if (aSec) {
4737:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4738:     ISGetIndices(aIS,&anchors);
4739:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4740:     /* figure out how many points are going to be in the new element matrix
4741:      * (we allow double counting, because it's all just going to be summed
4742:      * into the global matrix anyway) */
4743:     for (p = 0; p < 2*numPoints; p+=2) {
4744:       PetscInt b    = points[p];
4745:       PetscInt bDof = 0, bSecDof;

4747:       PetscSectionGetDof(section,b,&bSecDof);
4748:       if (!bSecDof) {
4749:         continue;
4750:       }
4751:       if (b >= aStart && b < aEnd) {
4752:         PetscSectionGetDof(aSec,b,&bDof);
4753:       }
4754:       if (bDof) {
4755:         /* this point is constrained */
4756:         /* it is going to be replaced by its anchors */
4757:         PetscInt bOff, q;

4759:         anyConstrained = PETSC_TRUE;
4760:         newNumPoints  += bDof;
4761:         PetscSectionGetOffset(aSec,b,&bOff);
4762:         for (q = 0; q < bDof; q++) {
4763:           PetscInt a = anchors[bOff + q];
4764:           PetscInt aDof;

4766:           PetscSectionGetDof(section,a,&aDof);
4767:           newNumIndices += aDof;
4768:           for (f = 0; f < numFields; ++f) {
4769:             PetscInt fDof;

4771:             PetscSectionGetFieldDof(section, a, f, &fDof);
4772:             newOffsets[f+1] += fDof;
4773:           }
4774:         }
4775:       }
4776:       else {
4777:         /* this point is not constrained */
4778:         newNumPoints++;
4779:         newNumIndices += bSecDof;
4780:         for (f = 0; f < numFields; ++f) {
4781:           PetscInt fDof;

4783:           PetscSectionGetFieldDof(section, b, f, &fDof);
4784:           newOffsets[f+1] += fDof;
4785:         }
4786:       }
4787:     }
4788:   }
4789:   if (!anyConstrained) {
4790:     if (outNumPoints)  *outNumPoints  = 0;
4791:     if (outNumIndices) *outNumIndices = 0;
4792:     if (outPoints)     *outPoints     = NULL;
4793:     if (outValues)     *outValues     = NULL;
4794:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4795:     return(0);
4796:   }

4798:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4799:   if (outNumIndices) *outNumIndices = newNumIndices;

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

4803:   if (!outPoints && !outValues) {
4804:     if (offsets) {
4805:       for (f = 0; f <= numFields; f++) {
4806:         offsets[f] = newOffsets[f];
4807:       }
4808:     }
4809:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4810:     return(0);
4811:   }

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

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

4817:   /* workspaces */
4818:   if (numFields) {
4819:     for (f = 0; f < numFields; f++) {
4820:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
4821:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
4822:     }
4823:   }
4824:   else {
4825:     DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
4826:     DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);
4827:   }

4829:   /* get workspaces for the point-to-point matrices */
4830:   if (numFields) {
4831:     PetscInt totalOffset, totalMatOffset;

4833:     for (p = 0; p < numPoints; p++) {
4834:       PetscInt b    = points[2*p];
4835:       PetscInt bDof = 0, bSecDof;

4837:       PetscSectionGetDof(section,b,&bSecDof);
4838:       if (!bSecDof) {
4839:         for (f = 0; f < numFields; f++) {
4840:           newPointOffsets[f][p + 1] = 0;
4841:           pointMatOffsets[f][p + 1] = 0;
4842:         }
4843:         continue;
4844:       }
4845:       if (b >= aStart && b < aEnd) {
4846:         PetscSectionGetDof(aSec, b, &bDof);
4847:       }
4848:       if (bDof) {
4849:         for (f = 0; f < numFields; f++) {
4850:           PetscInt fDof, q, bOff, allFDof = 0;

4852:           PetscSectionGetFieldDof(section, b, f, &fDof);
4853:           PetscSectionGetOffset(aSec, b, &bOff);
4854:           for (q = 0; q < bDof; q++) {
4855:             PetscInt a = anchors[bOff + q];
4856:             PetscInt aFDof;

4858:             PetscSectionGetFieldDof(section, a, f, &aFDof);
4859:             allFDof += aFDof;
4860:           }
4861:           newPointOffsets[f][p+1] = allFDof;
4862:           pointMatOffsets[f][p+1] = fDof * allFDof;
4863:         }
4864:       }
4865:       else {
4866:         for (f = 0; f < numFields; f++) {
4867:           PetscInt fDof;

4869:           PetscSectionGetFieldDof(section, b, f, &fDof);
4870:           newPointOffsets[f][p+1] = fDof;
4871:           pointMatOffsets[f][p+1] = 0;
4872:         }
4873:       }
4874:     }
4875:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
4876:       newPointOffsets[f][0] = totalOffset;
4877:       pointMatOffsets[f][0] = totalMatOffset;
4878:       for (p = 0; p < numPoints; p++) {
4879:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4880:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4881:       }
4882:       totalOffset    = newPointOffsets[f][numPoints];
4883:       totalMatOffset = pointMatOffsets[f][numPoints];
4884:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
4885:     }
4886:   }
4887:   else {
4888:     for (p = 0; p < numPoints; p++) {
4889:       PetscInt b    = points[2*p];
4890:       PetscInt bDof = 0, bSecDof;

4892:       PetscSectionGetDof(section,b,&bSecDof);
4893:       if (!bSecDof) {
4894:         newPointOffsets[0][p + 1] = 0;
4895:         pointMatOffsets[0][p + 1] = 0;
4896:         continue;
4897:       }
4898:       if (b >= aStart && b < aEnd) {
4899:         PetscSectionGetDof(aSec, b, &bDof);
4900:       }
4901:       if (bDof) {
4902:         PetscInt bOff, q, allDof = 0;

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

4908:           PetscSectionGetDof(section, a, &aDof);
4909:           allDof += aDof;
4910:         }
4911:         newPointOffsets[0][p+1] = allDof;
4912:         pointMatOffsets[0][p+1] = bSecDof * allDof;
4913:       }
4914:       else {
4915:         newPointOffsets[0][p+1] = bSecDof;
4916:         pointMatOffsets[0][p+1] = 0;
4917:       }
4918:     }
4919:     newPointOffsets[0][0] = 0;
4920:     pointMatOffsets[0][0] = 0;
4921:     for (p = 0; p < numPoints; p++) {
4922:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4923:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4924:     }
4925:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
4926:   }

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

4931:   /* get the point-to-point matrices; construct newPoints */
4932:   PetscSectionGetMaxDof(aSec, &maxAnchor);
4933:   PetscSectionGetMaxDof(section, &maxDof);
4934:   DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);
4935:   DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
4936:   if (numFields) {
4937:     for (p = 0, newP = 0; p < numPoints; p++) {
4938:       PetscInt b    = points[2*p];
4939:       PetscInt o    = points[2*p+1];
4940:       PetscInt bDof = 0, bSecDof;

4942:       PetscSectionGetDof(section, b, &bSecDof);
4943:       if (!bSecDof) {
4944:         continue;
4945:       }
4946:       if (b >= aStart && b < aEnd) {
4947:         PetscSectionGetDof(aSec, b, &bDof);
4948:       }
4949:       if (bDof) {
4950:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

4952:         fStart[0] = 0;
4953:         fEnd[0]   = 0;
4954:         for (f = 0; f < numFields; f++) {
4955:           PetscInt fDof;

4957:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
4958:           fStart[f+1] = fStart[f] + fDof;
4959:           fEnd[f+1]   = fStart[f+1];
4960:         }
4961:         PetscSectionGetOffset(cSec, b, &bOff);
4962:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

4964:         fAnchorStart[0] = 0;
4965:         fAnchorEnd[0]   = 0;
4966:         for (f = 0; f < numFields; f++) {
4967:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

4969:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4970:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4971:         }
4972:         PetscSectionGetOffset(aSec, b, &bOff);
4973:         for (q = 0; q < bDof; q++) {
4974:           PetscInt a = anchors[bOff + q], aOff;

4976:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4977:           newPoints[2*(newP + q)]     = a;
4978:           newPoints[2*(newP + q) + 1] = 0;
4979:           PetscSectionGetOffset(section, a, &aOff);
4980:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
4981:         }
4982:         newP += bDof;

4984:         if (outValues) {
4985:           /* get the point-to-point submatrix */
4986:           for (f = 0; f < numFields; f++) {
4987:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
4988:           }
4989:         }
4990:       }
4991:       else {
4992:         newPoints[2 * newP]     = b;
4993:         newPoints[2 * newP + 1] = o;
4994:         newP++;
4995:       }
4996:     }
4997:   } else {
4998:     for (p = 0; p < numPoints; p++) {
4999:       PetscInt b    = points[2*p];
5000:       PetscInt o    = points[2*p+1];
5001:       PetscInt bDof = 0, bSecDof;

5003:       PetscSectionGetDof(section, b, &bSecDof);
5004:       if (!bSecDof) {
5005:         continue;
5006:       }
5007:       if (b >= aStart && b < aEnd) {
5008:         PetscSectionGetDof(aSec, b, &bDof);
5009:       }
5010:       if (bDof) {
5011:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5022:           newPoints[2*(newP + q)]     = a;
5023:           newPoints[2*(newP + q) + 1] = 0;
5024:           PetscSectionGetOffset(section, a, &aOff);
5025:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5026:         }
5027:         newP += bDof;

5029:         /* get the point-to-point submatrix */
5030:         if (outValues) {
5031:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5032:         }
5033:       }
5034:       else {
5035:         newPoints[2 * newP]     = b;
5036:         newPoints[2 * newP + 1] = o;
5037:         newP++;
5038:       }
5039:     }
5040:   }

5042:   if (outValues) {
5043:     DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5044:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5045:     /* multiply constraints on the right */
5046:     if (numFields) {
5047:       for (f = 0; f < numFields; f++) {
5048:         PetscInt oldOff = offsets[f];

5050:         for (p = 0; p < numPoints; p++) {
5051:           PetscInt cStart = newPointOffsets[f][p];
5052:           PetscInt b      = points[2 * p];
5053:           PetscInt c, r, k;
5054:           PetscInt dof;

5056:           PetscSectionGetFieldDof(section,b,f,&dof);
5057:           if (!dof) {
5058:             continue;
5059:           }
5060:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5061:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5062:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5064:             for (r = 0; r < numIndices; r++) {
5065:               for (c = 0; c < nCols; c++) {
5066:                 for (k = 0; k < dof; k++) {
5067:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5068:                 }
5069:               }
5070:             }
5071:           }
5072:           else {
5073:             /* copy this column as is */
5074:             for (r = 0; r < numIndices; r++) {
5075:               for (c = 0; c < dof; c++) {
5076:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5077:               }
5078:             }
5079:           }
5080:           oldOff += dof;
5081:         }
5082:       }
5083:     }
5084:     else {
5085:       PetscInt oldOff = 0;
5086:       for (p = 0; p < numPoints; p++) {
5087:         PetscInt cStart = newPointOffsets[0][p];
5088:         PetscInt b      = points[2 * p];
5089:         PetscInt c, r, k;
5090:         PetscInt dof;

5092:         PetscSectionGetDof(section,b,&dof);
5093:         if (!dof) {
5094:           continue;
5095:         }
5096:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5097:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5098:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5100:           for (r = 0; r < numIndices; r++) {
5101:             for (c = 0; c < nCols; c++) {
5102:               for (k = 0; k < dof; k++) {
5103:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5104:               }
5105:             }
5106:           }
5107:         }
5108:         else {
5109:           /* copy this column as is */
5110:           for (r = 0; r < numIndices; r++) {
5111:             for (c = 0; c < dof; c++) {
5112:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5113:             }
5114:           }
5115:         }
5116:         oldOff += dof;
5117:       }
5118:     }

5120:     if (multiplyLeft) {
5121:       DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5122:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5123:       /* multiply constraints transpose on the left */
5124:       if (numFields) {
5125:         for (f = 0; f < numFields; f++) {
5126:           PetscInt oldOff = offsets[f];

5128:           for (p = 0; p < numPoints; p++) {
5129:             PetscInt rStart = newPointOffsets[f][p];
5130:             PetscInt b      = points[2 * p];
5131:             PetscInt c, r, k;
5132:             PetscInt dof;

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

5139:               for (r = 0; r < nRows; r++) {
5140:                 for (c = 0; c < newNumIndices; c++) {
5141:                   for (k = 0; k < dof; k++) {
5142:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5143:                   }
5144:                 }
5145:               }
5146:             }
5147:             else {
5148:               /* copy this row as is */
5149:               for (r = 0; r < dof; r++) {
5150:                 for (c = 0; c < newNumIndices; c++) {
5151:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5152:                 }
5153:               }
5154:             }
5155:             oldOff += dof;
5156:           }
5157:         }
5158:       }
5159:       else {
5160:         PetscInt oldOff = 0;

5162:         for (p = 0; p < numPoints; p++) {
5163:           PetscInt rStart = newPointOffsets[0][p];
5164:           PetscInt b      = points[2 * p];
5165:           PetscInt c, r, k;
5166:           PetscInt dof;

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

5173:             for (r = 0; r < nRows; r++) {
5174:               for (c = 0; c < newNumIndices; c++) {
5175:                 for (k = 0; k < dof; k++) {
5176:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5177:                 }
5178:               }
5179:             }
5180:           }
5181:           else {
5182:             /* copy this row as is */
5183:             for (r = 0; r < dof; r++) {
5184:               for (c = 0; c < newNumIndices; c++) {
5185:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5186:               }
5187:             }
5188:           }
5189:           oldOff += dof;
5190:         }
5191:       }

5193:       DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5194:     }
5195:     else {
5196:       newValues = tmpValues;
5197:     }
5198:   }

5200:   /* clean up */
5201:   DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);
5202:   DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);

5204:   if (numFields) {
5205:     for (f = 0; f < numFields; f++) {
5206:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
5207:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
5208:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
5209:     }
5210:   }
5211:   else {
5212:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
5213:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
5214:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);
5215:   }
5216:   ISRestoreIndices(aIS,&anchors);

5218:   /* output */
5219:   if (outPoints) {
5220:     *outPoints = newPoints;
5221:   }
5222:   else {
5223:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5224:   }
5225:   if (outValues) {
5226:     *outValues = newValues;
5227:   }
5228:   for (f = 0; f <= numFields; f++) {
5229:     offsets[f] = newOffsets[f];
5230:   }
5231:   return(0);
5232: }

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

5237:   Not collective

5239:   Input Parameters:
5240: + dm - The DM
5241: . section - The section describing the layout in v, or NULL to use the default section
5242: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5243: - point - The mesh point

5245:   Output parameters:
5246: + numIndices - The number of indices
5247: . indices - The indices
5248: - outOffsets - Field offset if not NULL

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

5252:   Level: advanced

5254: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5255: @*/
5256: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5257: {
5258:   PetscSection    clSection;
5259:   IS              clPoints;
5260:   const PetscInt *clp;
5261:   const PetscInt  **perms[32] = {NULL};
5262:   PetscInt       *points = NULL, *pointsNew;
5263:   PetscInt        numPoints, numPointsNew;
5264:   PetscInt        offsets[32];
5265:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5266:   PetscErrorCode  ierr;

5274:   PetscSectionGetNumFields(section, &Nf);
5275:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5276:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5277:   /* Get points in closure */
5278:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5279:   /* Get number of indices and indices per field */
5280:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5281:     PetscInt dof, fdof;

5283:     PetscSectionGetDof(section, points[p], &dof);
5284:     for (f = 0; f < Nf; ++f) {
5285:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5286:       offsets[f+1] += fdof;
5287:     }
5288:     Nind += dof;
5289:   }
5290:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5291:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5292:   if (!Nf) offsets[1] = Nind;
5293:   /* Get dual space symmetries */
5294:   for (f = 0; f < PetscMax(1,Nf); f++) {
5295:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5296:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5297:   }
5298:   /* Correct for hanging node constraints */
5299:   {
5300:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5301:     if (numPointsNew) {
5302:       for (f = 0; f < PetscMax(1,Nf); f++) {
5303:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5304:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5305:       }
5306:       for (f = 0; f < PetscMax(1,Nf); f++) {
5307:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5308:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5309:       }
5310:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5311:       numPoints = numPointsNew;
5312:       Nind      = NindNew;
5313:       points    = pointsNew;
5314:     }
5315:   }
5316:   /* Calculate indices */
5317:   DMGetWorkArray(dm, Nind, PETSC_INT, indices);
5318:   if (Nf) {
5319:     if (outOffsets) {
5320:       PetscInt f;

5322:       for (f = 0; f <= Nf; f++) {
5323:         outOffsets[f] = offsets[f];
5324:       }
5325:     }
5326:     for (p = 0; p < numPoints; p++) {
5327:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5328:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5329:     }
5330:   } else {
5331:     for (p = 0, off = 0; p < numPoints; p++) {
5332:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5334:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5335:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5336:     }
5337:   }
5338:   /* Cleanup points */
5339:   for (f = 0; f < PetscMax(1,Nf); f++) {
5340:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5341:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5342:   }
5343:   if (numPointsNew) {
5344:     DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);
5345:   } else {
5346:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5347:   }
5348:   if (numIndices) *numIndices = Nind;
5349:   return(0);
5350: }

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

5355:   Not collective

5357:   Input Parameters:
5358: + dm - The DM
5359: . section - The section describing the layout in v, or NULL to use the default section
5360: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5361: . point - The mesh point
5362: . numIndices - The number of indices
5363: . indices - The indices
5364: - outOffsets - Field offset if not NULL

5366:   Level: advanced

5368: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5369: @*/
5370: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5371: {

5377:   DMRestoreWorkArray(dm, 0, PETSC_INT, indices);
5378:   return(0);
5379: }

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

5384:   Not collective

5386:   Input Parameters:
5387: + dm - The DM
5388: . section - The section describing the layout in v, or NULL to use the default section
5389: . globalSection - The section describing the layout in v, or NULL to use the default global section
5390: . A - The matrix
5391: . point - The sieve point in the DM
5392: . values - The array of values
5393: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5398:   Level: intermediate

5400: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5401: @*/
5402: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5403: {
5404:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5405:   PetscSection        clSection;
5406:   IS                  clPoints;
5407:   PetscInt           *points = NULL, *newPoints;
5408:   const PetscInt     *clp;
5409:   PetscInt           *indices;
5410:   PetscInt            offsets[32];
5411:   const PetscInt    **perms[32] = {NULL};
5412:   const PetscScalar **flips[32] = {NULL};
5413:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5414:   PetscScalar        *valCopy = NULL;
5415:   PetscScalar        *newValues;
5416:   PetscErrorCode      ierr;

5420:   if (!section) {DMGetDefaultSection(dm, &section);}
5422:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5425:   PetscSectionGetNumFields(section, &numFields);
5426:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5427:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5428:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5429:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5430:     PetscInt fdof;

5432:     PetscSectionGetDof(section, points[p], &dof);
5433:     for (f = 0; f < numFields; ++f) {
5434:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5435:       offsets[f+1] += fdof;
5436:     }
5437:     numIndices += dof;
5438:   }
5439:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5453:         if (!numFields) {
5454:           PetscSectionGetDof(section,point,&fdof);
5455:         } else {
5456:           PetscSectionGetFieldDof(section,point,f,&fdof);
5457:         }
5458:         if (flip) {
5459:           PetscInt i, j, k;

5461:           if (!valCopy) {
5462:             DMGetWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5463:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5464:             values = valCopy;
5465:           }
5466:           for (i = 0; i < fdof; i++) {
5467:             PetscScalar fval = flip[i];

5469:             for (k = 0; k < numIndices; k++) {
5470:               valCopy[numIndices * (foffset + i) + k] *= fval;
5471:               valCopy[numIndices * k + (foffset + i)] *= fval;
5472:             }
5473:           }
5474:         }
5475:         foffset += fdof;
5476:       }
5477:     }
5478:   }
5479:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5480:   if (newNumPoints) {
5481:     if (valCopy) {
5482:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5483:     }
5484:     for (f = 0; f < PetscMax(1,numFields); f++) {
5485:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5486:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5487:     }
5488:     for (f = 0; f < PetscMax(1,numFields); f++) {
5489:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5490:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5491:     }
5492:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5493:     numPoints  = newNumPoints;
5494:     numIndices = newNumIndices;
5495:     points     = newPoints;
5496:     values     = newValues;
5497:   }
5498:   DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
5499:   if (numFields) {
5500:     for (p = 0; p < numPoints; p++) {
5501:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5502:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5503:     }
5504:   } else {
5505:     for (p = 0, off = 0; p < numPoints; p++) {
5506:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5507:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5508:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5509:     }
5510:   }
5511:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5512:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5513:   if (mesh->printFEM > 1) {
5514:     PetscInt i;
5515:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5516:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5517:     PetscPrintf(PETSC_COMM_SELF, "\n");
5518:   }
5519:   if (ierr) {
5520:     PetscMPIInt    rank;
5521:     PetscErrorCode ierr2;

5523:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5524:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5525:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5526:     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5527: 
5528:   }
5529:   for (f = 0; f < PetscMax(1,numFields); f++) {
5530:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5531:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5532:   }
5533:   if (newNumPoints) {
5534:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5535:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5536:   }
5537:   else {
5538:     if (valCopy) {
5539:       DMRestoreWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5540:     }
5541:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5542:   }
5543:   DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
5544:   return(0);
5545: }

5547: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5548: {
5549:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5550:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5551:   PetscInt       *cpoints = NULL;
5552:   PetscInt       *findices, *cindices;
5553:   PetscInt        foffsets[32], coffsets[32];
5554:   CellRefiner     cellRefiner;
5555:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5556:   PetscErrorCode  ierr;

5561:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5563:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5565:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5567:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5570:   PetscSectionGetNumFields(fsection, &numFields);
5571:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5572:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5573:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5574:   /* Column indices */
5575:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5576:   maxFPoints = numCPoints;
5577:   /* Compress out points not in the section */
5578:   /*   TODO: Squeeze out points with 0 dof as well */
5579:   PetscSectionGetChart(csection, &pStart, &pEnd);
5580:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5581:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5582:       cpoints[q*2]   = cpoints[p];
5583:       cpoints[q*2+1] = cpoints[p+1];
5584:       ++q;
5585:     }
5586:   }
5587:   numCPoints = q;
5588:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5589:     PetscInt fdof;

5591:     PetscSectionGetDof(csection, cpoints[p], &dof);
5592:     if (!dof) continue;
5593:     for (f = 0; f < numFields; ++f) {
5594:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5595:       coffsets[f+1] += fdof;
5596:     }
5597:     numCIndices += dof;
5598:   }
5599:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5600:   /* Row indices */
5601:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5602:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5603:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5604:   for (r = 0, q = 0; r < numSubcells; ++r) {
5605:     /* TODO Map from coarse to fine cells */
5606:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5607:     /* Compress out points not in the section */
5608:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5609:     for (p = 0; p < numFPoints*2; p += 2) {
5610:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5611:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5612:         if (!dof) continue;
5613:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5614:         if (s < q) continue;
5615:         ftotpoints[q*2]   = fpoints[p];
5616:         ftotpoints[q*2+1] = fpoints[p+1];
5617:         ++q;
5618:       }
5619:     }
5620:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5621:   }
5622:   numFPoints = q;
5623:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5624:     PetscInt fdof;

5626:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5627:     if (!dof) continue;
5628:     for (f = 0; f < numFields; ++f) {
5629:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5630:       foffsets[f+1] += fdof;
5631:     }
5632:     numFIndices += dof;
5633:   }
5634:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5636:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5637:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5638:   DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5639:   DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5640:   if (numFields) {
5641:     const PetscInt **permsF[32] = {NULL};
5642:     const PetscInt **permsC[32] = {NULL};

5644:     for (f = 0; f < numFields; f++) {
5645:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5646:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5647:     }
5648:     for (p = 0; p < numFPoints; p++) {
5649:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5650:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5651:     }
5652:     for (p = 0; p < numCPoints; p++) {
5653:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5654:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5655:     }
5656:     for (f = 0; f < numFields; f++) {
5657:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5658:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5659:     }
5660:   } else {
5661:     const PetscInt **permsF = NULL;
5662:     const PetscInt **permsC = NULL;

5664:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5665:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5666:     for (p = 0, off = 0; p < numFPoints; p++) {
5667:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5669:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5670:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5671:     }
5672:     for (p = 0, off = 0; p < numCPoints; p++) {
5673:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5675:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5676:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5677:     }
5678:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5679:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5680:   }
5681:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5682:   /* TODO: flips */
5683:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5684:   if (ierr) {
5685:     PetscMPIInt    rank;
5686:     PetscErrorCode ierr2;

5688:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5689:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5690:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5691:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5692:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5693: 
5694:   }
5695:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5696:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5697:   DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5698:   DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5699:   return(0);
5700: }

5702: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5703: {
5704:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5705:   PetscInt      *cpoints = NULL;
5706:   PetscInt       foffsets[32], coffsets[32];
5707:   CellRefiner    cellRefiner;
5708:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

5714:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5716:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5718:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5720:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5722:   PetscSectionGetNumFields(fsection, &numFields);
5723:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5724:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5725:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5726:   /* Column indices */
5727:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5728:   maxFPoints = numCPoints;
5729:   /* Compress out points not in the section */
5730:   /*   TODO: Squeeze out points with 0 dof as well */
5731:   PetscSectionGetChart(csection, &pStart, &pEnd);
5732:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5733:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5734:       cpoints[q*2]   = cpoints[p];
5735:       cpoints[q*2+1] = cpoints[p+1];
5736:       ++q;
5737:     }
5738:   }
5739:   numCPoints = q;
5740:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5741:     PetscInt fdof;

5743:     PetscSectionGetDof(csection, cpoints[p], &dof);
5744:     if (!dof) continue;
5745:     for (f = 0; f < numFields; ++f) {
5746:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5747:       coffsets[f+1] += fdof;
5748:     }
5749:     numCIndices += dof;
5750:   }
5751:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5752:   /* Row indices */
5753:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5754:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5755:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);
5756:   for (r = 0, q = 0; r < numSubcells; ++r) {
5757:     /* TODO Map from coarse to fine cells */
5758:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5759:     /* Compress out points not in the section */
5760:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5761:     for (p = 0; p < numFPoints*2; p += 2) {
5762:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5763:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5764:         if (!dof) continue;
5765:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5766:         if (s < q) continue;
5767:         ftotpoints[q*2]   = fpoints[p];
5768:         ftotpoints[q*2+1] = fpoints[p+1];
5769:         ++q;
5770:       }
5771:     }
5772:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5773:   }
5774:   numFPoints = q;
5775:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5776:     PetscInt fdof;

5778:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5779:     if (!dof) continue;
5780:     for (f = 0; f < numFields; ++f) {
5781:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5782:       foffsets[f+1] += fdof;
5783:     }
5784:     numFIndices += dof;
5785:   }
5786:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

5794:     for (f = 0; f < numFields; f++) {
5795:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5796:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5797:     }
5798:     for (p = 0; p < numFPoints; p++) {
5799:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5800:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5801:     }
5802:     for (p = 0; p < numCPoints; p++) {
5803:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5804:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5805:     }
5806:     for (f = 0; f < numFields; f++) {
5807:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5808:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5809:     }
5810:   } else {
5811:     const PetscInt **permsF = NULL;
5812:     const PetscInt **permsC = NULL;

5814:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5815:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5816:     for (p = 0, off = 0; p < numFPoints; p++) {
5817:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5819:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5820:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5821:     }
5822:     for (p = 0, off = 0; p < numCPoints; p++) {
5823:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5825:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5826:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5827:     }
5828:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5829:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5830:   }
5831:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5832:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5833:   return(0);
5834: }

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

5839:   Input Parameter:
5840: . dm - The DMPlex object

5842:   Output Parameters:
5843: + cMax - The first hybrid cell
5844: . fMax - The first hybrid face
5845: . eMax - The first hybrid edge
5846: - vMax - The first hybrid vertex

5848:   Level: developer

5850: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5851: @*/
5852: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5853: {
5854:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5855:   PetscInt       dim;

5860:   DMGetDimension(dm, &dim);
5861:   if (cMax) *cMax = mesh->hybridPointMax[dim];
5862:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5863:   if (eMax) *eMax = mesh->hybridPointMax[1];
5864:   if (vMax) *vMax = mesh->hybridPointMax[0];
5865:   return(0);
5866: }

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

5871:   Input Parameters:
5872: . dm   - The DMPlex object
5873: . cMax - The first hybrid cell
5874: . fMax - The first hybrid face
5875: . eMax - The first hybrid edge
5876: - vMax - The first hybrid vertex

5878:   Level: developer

5880: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5881: @*/
5882: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5883: {
5884:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5885:   PetscInt       dim;

5890:   DMGetDimension(dm, &dim);
5891:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5892:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5893:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5894:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5895:   return(0);
5896: }

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

5901:   Input Parameter:
5902: . dm   - The DMPlex object

5904:   Output Parameter:
5905: . cellHeight - The height of a cell

5907:   Level: developer

5909: .seealso DMPlexSetVTKCellHeight()
5910: @*/
5911: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5912: {
5913:   DM_Plex *mesh = (DM_Plex*) dm->data;

5918:   *cellHeight = mesh->vtkCellHeight;
5919:   return(0);
5920: }

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

5925:   Input Parameters:
5926: + dm   - The DMPlex object
5927: - cellHeight - The height of a cell

5929:   Level: developer

5931: .seealso DMPlexGetVTKCellHeight()
5932: @*/
5933: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5934: {
5935:   DM_Plex *mesh = (DM_Plex*) dm->data;

5939:   mesh->vtkCellHeight = cellHeight;
5940:   return(0);
5941: }

5943: /* We can easily have a form that takes an IS instead */
5944: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5945: {
5946:   PetscSection   section, globalSection;
5947:   PetscInt      *numbers, p;

5951:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
5952:   PetscSectionSetChart(section, pStart, pEnd);
5953:   for (p = pStart; p < pEnd; ++p) {
5954:     PetscSectionSetDof(section, p, 1);
5955:   }
5956:   PetscSectionSetUp(section);
5957:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
5958:   PetscMalloc1(pEnd - pStart, &numbers);
5959:   for (p = pStart; p < pEnd; ++p) {
5960:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
5961:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5962:     else                       numbers[p-pStart] += shift;
5963:   }
5964:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
5965:   if (globalSize) {
5966:     PetscLayout layout;
5967:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
5968:     PetscLayoutGetSize(layout, globalSize);
5969:     PetscLayoutDestroy(&layout);
5970:   }
5971:   PetscSectionDestroy(&section);
5972:   PetscSectionDestroy(&globalSection);
5973:   return(0);
5974: }

5976: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5977: {
5978:   PetscInt       cellHeight, cStart, cEnd, cMax;

5982:   DMPlexGetVTKCellHeight(dm, &cellHeight);
5983:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5984:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5985:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5986:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
5987:   return(0);
5988: }

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

5993:   Input Parameter:
5994: . dm   - The DMPlex object

5996:   Output Parameter:
5997: . globalCellNumbers - Global cell numbers for all cells on this process

5999:   Level: developer

6001: .seealso DMPlexGetVertexNumbering()
6002: @*/
6003: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6004: {
6005:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6010:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6011:   *globalCellNumbers = mesh->globalCellNumbers;
6012:   return(0);
6013: }

6015: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6016: {
6017:   PetscInt       vStart, vEnd, vMax;

6022:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6023:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6024:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6025:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6026:   return(0);
6027: }

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

6032:   Input Parameter:
6033: . dm   - The DMPlex object

6035:   Output Parameter:
6036: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6038:   Level: developer

6040: .seealso DMPlexGetCellNumbering()
6041: @*/
6042: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6043: {
6044:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6049:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6050:   *globalVertexNumbers = mesh->globalVertexNumbers;
6051:   return(0);
6052: }

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

6057:   Input Parameter:
6058: . dm   - The DMPlex object

6060:   Output Parameter:
6061: . globalPointNumbers - Global numbers for all points on this process

6063:   Level: developer

6065: .seealso DMPlexGetCellNumbering()
6066: @*/
6067: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6068: {
6069:   IS             nums[4];
6070:   PetscInt       depths[4];
6071:   PetscInt       depth, d, shift = 0;

6076:   DMPlexGetDepth(dm, &depth);
6077:   /* For unstratified meshes use dim instead of depth */
6078:   if (depth < 0) {DMGetDimension(dm, &depth);}
6079:   depths[0] = depth; depths[1] = 0;
6080:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6081:   for (d = 0; d <= depth; ++d) {
6082:     PetscInt pStart, pEnd, gsize;

6084:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6085:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6086:     shift += gsize;
6087:   }
6088:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6089:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6090:   return(0);
6091: }

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

6096:   Input Parameters:
6097:   + dm - The DMPlex object

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

6101:   Level: developer

6103: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6104: @*/
6105: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6106: {
6107:   PetscSection    coneSection, supportSection;
6108:   const PetscInt *cone, *support;
6109:   PetscInt        coneSize, c, supportSize, s;
6110:   PetscInt        pStart, pEnd, p, csize, ssize;
6111:   PetscErrorCode  ierr;

6115:   DMPlexGetConeSection(dm, &coneSection);
6116:   DMPlexGetSupportSection(dm, &supportSection);
6117:   /* Check that point p is found in the support of its cone points, and vice versa */
6118:   DMPlexGetChart(dm, &pStart, &pEnd);
6119:   for (p = pStart; p < pEnd; ++p) {
6120:     DMPlexGetConeSize(dm, p, &coneSize);
6121:     DMPlexGetCone(dm, p, &cone);
6122:     for (c = 0; c < coneSize; ++c) {
6123:       PetscBool dup = PETSC_FALSE;
6124:       PetscInt  d;
6125:       for (d = c-1; d >= 0; --d) {
6126:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6127:       }
6128:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6129:       DMPlexGetSupport(dm, cone[c], &support);
6130:       for (s = 0; s < supportSize; ++s) {
6131:         if (support[s] == p) break;
6132:       }
6133:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6134:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6135:         for (s = 0; s < coneSize; ++s) {
6136:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6137:         }
6138:         PetscPrintf(PETSC_COMM_SELF, "\n");
6139:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6140:         for (s = 0; s < supportSize; ++s) {
6141:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6142:         }
6143:         PetscPrintf(PETSC_COMM_SELF, "\n");
6144:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6145:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6146:       }
6147:     }
6148:     DMPlexGetSupportSize(dm, p, &supportSize);
6149:     DMPlexGetSupport(dm, p, &support);
6150:     for (s = 0; s < supportSize; ++s) {
6151:       DMPlexGetConeSize(dm, support[s], &coneSize);
6152:       DMPlexGetCone(dm, support[s], &cone);
6153:       for (c = 0; c < coneSize; ++c) {
6154:         if (cone[c] == p) break;
6155:       }
6156:       if (c >= coneSize) {
6157:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6158:         for (c = 0; c < supportSize; ++c) {
6159:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6160:         }
6161:         PetscPrintf(PETSC_COMM_SELF, "\n");
6162:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6163:         for (c = 0; c < coneSize; ++c) {
6164:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6165:         }
6166:         PetscPrintf(PETSC_COMM_SELF, "\n");
6167:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6168:       }
6169:     }
6170:   }
6171:   PetscSectionGetStorageSize(coneSection, &csize);
6172:   PetscSectionGetStorageSize(supportSection, &ssize);
6173:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6174:   return(0);
6175: }

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

6180:   Input Parameters:
6181: + dm - The DMPlex object
6182: . isSimplex - Are the cells simplices or tensor products
6183: - cellHeight - Normally 0

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

6187:   Level: developer

6189: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6190: @*/
6191: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6192: {
6193:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6198:   DMGetDimension(dm, &dim);
6199:   switch (dim) {
6200:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6201:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6202:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6203:   default:
6204:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6205:   }
6206:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6207:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6208:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6209:   cMax = cMax >= 0 ? cMax : cEnd;
6210:   for (c = cStart; c < cMax; ++c) {
6211:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6213:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6214:     for (cl = 0; cl < closureSize*2; cl += 2) {
6215:       const PetscInt p = closure[cl];
6216:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6217:     }
6218:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6219:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6220:   }
6221:   for (c = cMax; c < cEnd; ++c) {
6222:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6224:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6225:     for (cl = 0; cl < closureSize*2; cl += 2) {
6226:       const PetscInt p = closure[cl];
6227:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6228:     }
6229:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6230:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6231:   }
6232:   return(0);
6233: }

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

6238:   Input Parameters:
6239: + dm - The DMPlex object
6240: . isSimplex - Are the cells simplices or tensor products
6241: - cellHeight - Normally 0

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

6245:   Level: developer

6247: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6248: @*/
6249: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6250: {
6251:   PetscInt       pMax[4];
6252:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

6257:   DMGetDimension(dm, &dim);
6258:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6259:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6260:   for (h = cellHeight; h < dim; ++h) {
6261:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6262:     for (c = cStart; c < cEnd; ++c) {
6263:       const PetscInt *cone, *ornt, *faces;
6264:       PetscInt        numFaces, faceSize, coneSize,f;
6265:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6267:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6268:       DMPlexGetConeSize(dm, c, &coneSize);
6269:       DMPlexGetCone(dm, c, &cone);
6270:       DMPlexGetConeOrientation(dm, c, &ornt);
6271:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6272:       for (cl = 0; cl < closureSize*2; cl += 2) {
6273:         const PetscInt p = closure[cl];
6274:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6275:       }
6276:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6277:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6278:       for (f = 0; f < numFaces; ++f) {
6279:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6281:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6282:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6283:           const PetscInt p = fclosure[cl];
6284:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6285:         }
6286:         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);
6287:         for (v = 0; v < fnumCorners; ++v) {
6288:           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]);
6289:         }
6290:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6291:       }
6292:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6293:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6294:     }
6295:   }
6296:   return(0);
6297: }

6299: /* Pointwise interpolation
6300:      Just code FEM for now
6301:      u^f = I u^c
6302:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6303:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6304:      I_{ij} = psi^f_i phi^c_j
6305: */
6306: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6307: {
6308:   PetscSection   gsc, gsf;
6309:   PetscInt       m, n;
6310:   void          *ctx;
6311:   DM             cdm;
6312:   PetscBool      regular;

6316:   DMGetDefaultGlobalSection(dmFine, &gsf);
6317:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6318:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6319:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6321:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6322:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6323:   MatSetType(*interpolation, dmCoarse->mattype);
6324:   DMGetApplicationContext(dmFine, &ctx);

6326:   DMGetCoarseDM(dmFine, &cdm);
6327:   DMPlexGetRegularRefinement(dmFine, &regular);
6328:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6329:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6330:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6331:   /* Use naive scaling */
6332:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6333:   return(0);
6334: }

6336: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6337: {
6339:   VecScatter     ctx;

6342:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6343:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6344:   VecScatterDestroy(&ctx);
6345:   return(0);
6346: }

6348: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6349: {
6350:   PetscSection   section;
6351:   IS            *bcPoints, *bcComps;
6352:   PetscBool     *isFE;
6353:   PetscInt      *bcFields, *numComp, *numDof;
6354:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6355:   PetscInt       cStart, cEnd, cEndInterior;

6359:   DMGetNumFields(dm, &numFields);
6360:   if (!numFields) return(0);
6361:   /* FE and FV boundary conditions are handled slightly differently */
6362:   PetscMalloc1(numFields, &isFE);
6363:   for (f = 0; f < numFields; ++f) {
6364:     PetscObject  obj;
6365:     PetscClassId id;

6367:     DMGetField(dm, f, &obj);
6368:     PetscObjectGetClassId(obj, &id);
6369:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6370:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6371:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6372:   }
6373:   /* Allocate boundary point storage for FEM boundaries */
6374:   DMPlexGetDepth(dm, &depth);
6375:   DMGetDimension(dm, &dim);
6376:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6377:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6378:   PetscDSGetNumBoundary(dm->prob, &numBd);
6379:   for (bd = 0; bd < numBd; ++bd) {
6380:     PetscInt                field;
6381:     DMBoundaryConditionType type;
6382:     const char             *labelName;
6383:     DMLabel                 label;

6385:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6386:     DMGetLabel(dm,labelName,&label);
6387:     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6388:   }
6389:   /* Add ghost cell boundaries for FVM */
6390:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6391:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6392:   /* Constrain ghost cells for FV */
6393:   for (f = 0; f < numFields; ++f) {
6394:     PetscInt *newidx, c;

6396:     if (isFE[f] || cEndInterior < 0) continue;
6397:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6398:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6399:     bcFields[bc] = f;
6400:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6401:   }
6402:   /* Handle FEM Dirichlet boundaries */
6403:   for (bd = 0; bd < numBd; ++bd) {
6404:     const char             *bdLabel;
6405:     DMLabel                 label;
6406:     const PetscInt         *comps;
6407:     const PetscInt         *values;
6408:     PetscInt                bd2, field, numComps, numValues;
6409:     DMBoundaryConditionType type;
6410:     PetscBool               duplicate = PETSC_FALSE;

6412:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6413:     DMGetLabel(dm, bdLabel, &label);
6414:     if (!isFE[field] || !label) continue;
6415:     /* Only want to modify label once */
6416:     for (bd2 = 0; bd2 < bd; ++bd2) {
6417:       const char *bdname;
6418:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6419:       PetscStrcmp(bdname, bdLabel, &duplicate);
6420:       if (duplicate) break;
6421:     }
6422:     if (!duplicate && (isFE[field])) {
6423:       /* don't complete cells, which are just present to give orientation to the boundary */
6424:       DMPlexLabelComplete(dm, label);
6425:     }
6426:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6427:     if (type & DM_BC_ESSENTIAL) {
6428:       PetscInt       *newidx;
6429:       PetscInt        n, newn = 0, p, v;

6431:       bcFields[bc] = field;
6432:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6433:       for (v = 0; v < numValues; ++v) {
6434:         IS              tmp;
6435:         const PetscInt *idx;

6437:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6438:         if (!tmp) continue;
6439:         ISGetLocalSize(tmp, &n);
6440:         ISGetIndices(tmp, &idx);
6441:         if (isFE[field]) {
6442:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6443:         } else {
6444:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6445:         }
6446:         ISRestoreIndices(tmp, &idx);
6447:         ISDestroy(&tmp);
6448:       }
6449:       PetscMalloc1(newn,&newidx);
6450:       newn = 0;
6451:       for (v = 0; v < numValues; ++v) {
6452:         IS              tmp;
6453:         const PetscInt *idx;

6455:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6456:         if (!tmp) continue;
6457:         ISGetLocalSize(tmp, &n);
6458:         ISGetIndices(tmp, &idx);
6459:         if (isFE[field]) {
6460:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6461:         } else {
6462:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6463:         }
6464:         ISRestoreIndices(tmp, &idx);
6465:         ISDestroy(&tmp);
6466:       }
6467:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6468:     }
6469:   }
6470:   /* Handle discretization */
6471:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6472:   for (f = 0; f < numFields; ++f) {
6473:     PetscObject obj;

6475:     DMGetField(dm, f, &obj);
6476:     if (isFE[f]) {
6477:       PetscFE         fe = (PetscFE) obj;
6478:       const PetscInt *numFieldDof;
6479:       PetscInt        d;

6481:       PetscFEGetNumComponents(fe, &numComp[f]);
6482:       PetscFEGetNumDof(fe, &numFieldDof);
6483:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6484:     } else {
6485:       PetscFV fv = (PetscFV) obj;

6487:       PetscFVGetNumComponents(fv, &numComp[f]);
6488:       numDof[f*(dim+1)+dim] = numComp[f];
6489:     }
6490:   }
6491:   for (f = 0; f < numFields; ++f) {
6492:     PetscInt d;
6493:     for (d = 1; d < dim; ++d) {
6494:       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.");
6495:     }
6496:   }
6497:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6498:   for (f = 0; f < numFields; ++f) {
6499:     PetscFE     fe;
6500:     const char *name;

6502:     DMGetField(dm, f, (PetscObject *) &fe);
6503:     PetscObjectGetName((PetscObject) fe, &name);
6504:     PetscSectionSetFieldName(section, f, name);
6505:   }
6506:   DMSetDefaultSection(dm, section);
6507:   PetscSectionDestroy(&section);
6508:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6509:   PetscFree3(bcFields,bcPoints,bcComps);
6510:   PetscFree2(numComp,numDof);
6511:   PetscFree(isFE);
6512:   return(0);
6513: }

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

6518:   Input Parameter:
6519: . dm - The DMPlex object

6521:   Output Parameter:
6522: . regular - The flag

6524:   Level: intermediate

6526: .seealso: DMPlexSetRegularRefinement()
6527: @*/
6528: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6529: {
6533:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6534:   return(0);
6535: }

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

6540:   Input Parameters:
6541: + dm - The DMPlex object
6542: - regular - The flag

6544:   Level: intermediate

6546: .seealso: DMPlexGetRegularRefinement()
6547: @*/
6548: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6549: {
6552:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6553:   return(0);
6554: }

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

6561:   not collective

6563:   Input Parameters:
6564: . dm - The DMPlex object

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


6571:   Level: intermediate

6573: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6574: @*/
6575: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6576: {
6577:   DM_Plex *plex = (DM_Plex *)dm->data;

6582:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6583:   if (anchorSection) *anchorSection = plex->anchorSection;
6584:   if (anchorIS) *anchorIS = plex->anchorIS;
6585:   return(0);
6586: }

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

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

6596:   collective on dm

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

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

6605:   Level: intermediate

6607: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6608: @*/
6609: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6610: {
6611:   DM_Plex        *plex = (DM_Plex *)dm->data;
6612:   PetscMPIInt    result;

6617:   if (anchorSection) {
6619:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6620:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6621:   }
6622:   if (anchorIS) {
6624:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6625:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6626:   }

6628:   PetscObjectReference((PetscObject)anchorSection);
6629:   PetscSectionDestroy(&plex->anchorSection);
6630:   plex->anchorSection = anchorSection;

6632:   PetscObjectReference((PetscObject)anchorIS);
6633:   ISDestroy(&plex->anchorIS);
6634:   plex->anchorIS = anchorIS;

6636: #if defined(PETSC_USE_DEBUG)
6637:   if (anchorIS && anchorSection) {
6638:     PetscInt size, a, pStart, pEnd;
6639:     const PetscInt *anchors;

6641:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6642:     ISGetLocalSize(anchorIS,&size);
6643:     ISGetIndices(anchorIS,&anchors);
6644:     for (a = 0; a < size; a++) {
6645:       PetscInt p;

6647:       p = anchors[a];
6648:       if (p >= pStart && p < pEnd) {
6649:         PetscInt dof;

6651:         PetscSectionGetDof(anchorSection,p,&dof);
6652:         if (dof) {
6653:           PetscErrorCode ierr2;

6655:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6656:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6657:         }
6658:       }
6659:     }
6660:     ISRestoreIndices(anchorIS,&anchors);
6661:   }
6662: #endif
6663:   /* reset the generic constraints */
6664:   DMSetDefaultConstraints(dm,NULL,NULL);
6665:   return(0);
6666: }

6668: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6669: {
6670:   PetscSection anchorSection;
6671:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

6676:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6677:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6678:   PetscSectionGetNumFields(section,&numFields);
6679:   if (numFields) {
6680:     PetscInt f;
6681:     PetscSectionSetNumFields(*cSec,numFields);

6683:     for (f = 0; f < numFields; f++) {
6684:       PetscInt numComp;

6686:       PetscSectionGetFieldComponents(section,f,&numComp);
6687:       PetscSectionSetFieldComponents(*cSec,f,numComp);
6688:     }
6689:   }
6690:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6691:   PetscSectionGetChart(section,&sStart,&sEnd);
6692:   pStart = PetscMax(pStart,sStart);
6693:   pEnd   = PetscMin(pEnd,sEnd);
6694:   pEnd   = PetscMax(pStart,pEnd);
6695:   PetscSectionSetChart(*cSec,pStart,pEnd);
6696:   for (p = pStart; p < pEnd; p++) {
6697:     PetscSectionGetDof(anchorSection,p,&dof);
6698:     if (dof) {
6699:       PetscSectionGetDof(section,p,&dof);
6700:       PetscSectionSetDof(*cSec,p,dof);
6701:       for (f = 0; f < numFields; f++) {
6702:         PetscSectionGetFieldDof(section,p,f,&dof);
6703:         PetscSectionSetFieldDof(*cSec,p,f,dof);
6704:       }
6705:     }
6706:   }
6707:   PetscSectionSetUp(*cSec);
6708:   return(0);
6709: }

6711: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6712: {
6713:   PetscSection aSec;
6714:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6715:   const PetscInt *anchors;
6716:   PetscInt numFields, f;
6717:   IS aIS;

6722:   PetscSectionGetStorageSize(cSec, &m);
6723:   PetscSectionGetStorageSize(section, &n);
6724:   MatCreate(PETSC_COMM_SELF,cMat);
6725:   MatSetSizes(*cMat,m,n,m,n);
6726:   MatSetType(*cMat,MATSEQAIJ);
6727:   DMPlexGetAnchors(dm,&aSec,&aIS);
6728:   ISGetIndices(aIS,&anchors);
6729:   /* cSec will be a subset of aSec and section */
6730:   PetscSectionGetChart(cSec,&pStart,&pEnd);
6731:   PetscMalloc1(m+1,&i);
6732:   i[0] = 0;
6733:   PetscSectionGetNumFields(section,&numFields);
6734:   for (p = pStart; p < pEnd; p++) {
6735:     PetscInt rDof, rOff, r;

6737:     PetscSectionGetDof(aSec,p,&rDof);
6738:     if (!rDof) continue;
6739:     PetscSectionGetOffset(aSec,p,&rOff);
6740:     if (numFields) {
6741:       for (f = 0; f < numFields; f++) {
6742:         annz = 0;
6743:         for (r = 0; r < rDof; r++) {
6744:           a = anchors[rOff + r];
6745:           PetscSectionGetFieldDof(section,a,f,&aDof);
6746:           annz += aDof;
6747:         }
6748:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6749:         PetscSectionGetFieldOffset(cSec,p,f,&off);
6750:         for (q = 0; q < dof; q++) {
6751:           i[off + q + 1] = i[off + q] + annz;
6752:         }
6753:       }
6754:     }
6755:     else {
6756:       annz = 0;
6757:       for (q = 0; q < dof; q++) {
6758:         a = anchors[off + q];
6759:         PetscSectionGetDof(section,a,&aDof);
6760:         annz += aDof;
6761:       }
6762:       PetscSectionGetDof(cSec,p,&dof);
6763:       PetscSectionGetOffset(cSec,p,&off);
6764:       for (q = 0; q < dof; q++) {
6765:         i[off + q + 1] = i[off + q] + annz;
6766:       }
6767:     }
6768:   }
6769:   nnz = i[m];
6770:   PetscMalloc1(nnz,&j);
6771:   offset = 0;
6772:   for (p = pStart; p < pEnd; p++) {
6773:     if (numFields) {
6774:       for (f = 0; f < numFields; f++) {
6775:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6776:         for (q = 0; q < dof; q++) {
6777:           PetscInt rDof, rOff, r;
6778:           PetscSectionGetDof(aSec,p,&rDof);
6779:           PetscSectionGetOffset(aSec,p,&rOff);
6780:           for (r = 0; r < rDof; r++) {
6781:             PetscInt s;

6783:             a = anchors[rOff + r];
6784:             PetscSectionGetFieldDof(section,a,f,&aDof);
6785:             PetscSectionGetFieldOffset(section,a,f,&aOff);
6786:             for (s = 0; s < aDof; s++) {
6787:               j[offset++] = aOff + s;
6788:             }
6789:           }
6790:         }
6791:       }
6792:     }
6793:     else {
6794:       PetscSectionGetDof(cSec,p,&dof);
6795:       for (q = 0; q < dof; q++) {
6796:         PetscInt rDof, rOff, r;
6797:         PetscSectionGetDof(aSec,p,&rDof);
6798:         PetscSectionGetOffset(aSec,p,&rOff);
6799:         for (r = 0; r < rDof; r++) {
6800:           PetscInt s;

6802:           a = anchors[rOff + r];
6803:           PetscSectionGetDof(section,a,&aDof);
6804:           PetscSectionGetOffset(section,a,&aOff);
6805:           for (s = 0; s < aDof; s++) {
6806:             j[offset++] = aOff + s;
6807:           }
6808:         }
6809:       }
6810:     }
6811:   }
6812:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
6813:   PetscFree(i);
6814:   PetscFree(j);
6815:   ISRestoreIndices(aIS,&anchors);
6816:   return(0);
6817: }

6819: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6820: {
6821:   DM_Plex        *plex = (DM_Plex *)dm->data;
6822:   PetscSection   anchorSection, section, cSec;
6823:   Mat            cMat;

6828:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6829:   if (anchorSection) {
6830:     PetscDS  ds;
6831:     PetscInt nf;

6833:     DMGetDefaultSection(dm,&section);
6834:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
6835:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
6836:     DMGetDS(dm,&ds);
6837:     PetscDSGetNumFields(ds,&nf);
6838:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
6839:     DMSetDefaultConstraints(dm,cSec,cMat);
6840:     PetscSectionDestroy(&cSec);
6841:     MatDestroy(&cMat);
6842:   }
6843:   return(0);
6844: }