Actual source code: plex.c

petsc-master 2020-01-22
Report Typos and Errors
  1:  #include <petsc/private/dmpleximpl.h>
  2:  #include <petsc/private/isimpl.h>
  3:  #include <petsc/private/vecimpl.h>
  4:  #include <petsc/private/glvisvecimpl.h>
  5:  #include <petscsf.h>
  6:  #include <petscds.h>
  7:  #include <petscdraw.h>
  8:  #include <petscdmfield.h>

 10: /* Logging support */
 11: PetscLogEvent DMPLEX_Interpolate, DMPLEX_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_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF;

 13: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

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

 19:   Collective

 21:   Input Parameters:
 22: . dm - The DMPlex object

 24:   Output Parameters:
 25: . dmRefined - The refined DMPlex object

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

 29:   Level: intermediate

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

 44:   DMGetDimension(dm, &dim);
 45:   DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);
 46:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
 47:   if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP;
 48:   else {
 49:     DMPlexGetCellType(dm, cStart, &ct);
 50:     switch (ct) {
 51:       case DM_POLYTOPE_POINT:
 52:       case DM_POLYTOPE_SEGMENT:
 53:         cellRefiner = REFINER_NOOP;break;
 54:       case DM_POLYTOPE_TRIANGLE:
 55:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
 56:         else           cellRefiner = REFINER_SIMPLEX_TO_HEX_2D;
 57:         break;
 58:       case DM_POLYTOPE_QUADRILATERAL:
 59:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D;
 60:         else           cellRefiner = REFINER_NOOP;
 61:         break;
 62:       case DM_POLYTOPE_TETRAHEDRON:
 63:         if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;
 64:         else           cellRefiner = REFINER_SIMPLEX_TO_HEX_3D;
 65:         break;
 66:       case DM_POLYTOPE_TRI_PRISM_TENSOR:
 67:         cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;break;
 68:       case DM_POLYTOPE_HEXAHEDRON:
 69:         if (cMax >= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Simplex2Tensor in 3D with Hybrid mesh not yet done");
 70:         else           cellRefiner = REFINER_NOOP;
 71:         break;
 72:       default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle cell polytope type %s", DMPolytopeTypes[ct]);
 73:     }
 74:   }
 75:   /* return if we don't need to refine */
 76:   lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE;
 77:   MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
 78:   if (allnoop) {
 79:     *dmRefined = NULL;
 80:     return(0);
 81:   }
 82:   DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
 83:   DMCopyBoundary(dm, *dmRefined);
 84:   DMGetCoordinatesLocalized(dm, &localized);
 85:   if (localized) {
 86:     DMLocalizeCoordinates(*dmRefined);
 87:   }
 88:   return(0);
 89: }

 91: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
 92: {
 93:   PetscInt       dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cMax;
 94:   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];

 98:   *ft  = PETSC_VTK_INVALID;
 99:   DMGetDimension(dm, &dim);
100:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
101:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
102:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
103:   cEnd = cMax < 0 ? cEnd : cMax;
104:   PetscSectionGetChart(section, &pStart, &pEnd);
105:   if (field >= 0) {
106:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);}
107:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);}
108:   } else {
109:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vcdof[0]);}
110:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &vcdof[1]);}
111:   }
112:   MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
113:   if (globalvcdof[0]) {
114:     *sStart = vStart;
115:     *sEnd   = vEnd;
116:     if (globalvcdof[0] == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
117:     else                       *ft = PETSC_VTK_POINT_FIELD;
118:   } else if (globalvcdof[1]) {
119:     *sStart = cStart;
120:     *sEnd   = cEnd;
121:     if (globalvcdof[1] == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
122:     else                       *ft = PETSC_VTK_CELL_FIELD;
123:   } else {
124:     if (field >= 0) {
125:       const char *fieldname;

127:       PetscSectionGetFieldName(section, field, &fieldname);
128:       PetscInfo2((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname);
129:     } else {
130:       PetscInfo((PetscObject) dm, "Could not classify VTK output typp of section\"%s\"\n");
131:     }
132:   }
133:   return(0);
134: }

136: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
137: {
138:   DM                 dm;
139:   PetscSection       s;
140:   PetscDraw          draw, popup;
141:   DM                 cdm;
142:   PetscSection       coordSection;
143:   Vec                coordinates;
144:   const PetscScalar *coords, *array;
145:   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
146:   PetscReal          vbound[2], time;
147:   PetscBool          isnull, flg;
148:   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
149:   const char        *name;
150:   char               title[PETSC_MAX_PATH_LEN];
151:   PetscErrorCode     ierr;

154:   PetscViewerDrawGetDraw(viewer, 0, &draw);
155:   PetscDrawIsNull(draw, &isnull);
156:   if (isnull) return(0);

158:   VecGetDM(v, &dm);
159:   DMGetCoordinateDim(dm, &dim);
160:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
161:   DMGetLocalSection(dm, &s);
162:   PetscSectionGetNumFields(s, &Nf);
163:   DMGetCoarsenLevel(dm, &level);
164:   DMGetCoordinateDM(dm, &cdm);
165:   DMGetLocalSection(cdm, &coordSection);
166:   DMGetCoordinatesLocal(dm, &coordinates);
167:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
168:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

170:   PetscObjectGetName((PetscObject) v, &name);
171:   DMGetOutputSequenceNumber(dm, &step, &time);

173:   VecGetLocalSize(coordinates, &N);
174:   VecGetArrayRead(coordinates, &coords);
175:   for (c = 0; c < N; c += dim) {
176:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
177:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
178:   }
179:   VecRestoreArrayRead(coordinates, &coords);
180:   PetscDrawClear(draw);

182:   /* Could implement something like DMDASelectFields() */
183:   for (f = 0; f < Nf; ++f) {
184:     DM   fdm = dm;
185:     Vec  fv  = v;
186:     IS   fis;
187:     char prefix[PETSC_MAX_PATH_LEN];
188:     const char *fname;

190:     PetscSectionGetFieldComponents(s, f, &Nc);
191:     PetscSectionGetFieldName(s, f, &fname);

193:     if (v->hdr.prefix) {PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));}
194:     else               {prefix[0] = '\0';}
195:     if (Nf > 1) {
196:       DMCreateSubDM(dm, 1, &f, &fis, &fdm);
197:       VecGetSubVector(v, fis, &fv);
198:       PetscStrlcat(prefix, fname,sizeof(prefix));
199:       PetscStrlcat(prefix, "_",sizeof(prefix));
200:     }
201:     for (comp = 0; comp < Nc; ++comp, ++w) {
202:       PetscInt nmax = 2;

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

209:       /* TODO Get max and min only for this component */
210:       PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);
211:       if (!flg) {
212:         VecMin(fv, NULL, &vbound[0]);
213:         VecMax(fv, NULL, &vbound[1]);
214:         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
215:       }
216:       PetscDrawGetPopup(draw, &popup);
217:       PetscDrawScalePopup(popup, vbound[0], vbound[1]);
218:       PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);

220:       VecGetArrayRead(fv, &array);
221:       for (c = cStart; c < cEnd; ++c) {
222:         PetscScalar *coords = NULL, *a = NULL;
223:         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};

225:         DMPlexPointLocalRead(fdm, c, array, &a);
226:         if (a) {
227:           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
228:           color[1] = color[2] = color[3] = color[0];
229:         } else {
230:           PetscScalar *vals = NULL;
231:           PetscInt     numVals, va;

233:           DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);
234:           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);
235:           switch (numVals/Nc) {
236:           case 3: /* P1 Triangle */
237:           case 4: /* P1 Quadrangle */
238:             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
239:             break;
240:           case 6: /* P2 Triangle */
241:           case 8: /* P2 Quadrangle */
242:             for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
243:             break;
244:           default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
245:           }
246:           DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);
247:         }
248:         DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
249:         switch (numCoords) {
250:         case 6:
251:           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]);
252:           break;
253:         case 8:
254:           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]);
255:           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]);
256:           break;
257:         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
258:         }
259:         DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
260:       }
261:       VecRestoreArrayRead(fv, &array);
262:       PetscDrawFlush(draw);
263:       PetscDrawPause(draw);
264:       PetscDrawSave(draw);
265:     }
266:     if (Nf > 1) {
267:       VecRestoreSubVector(v, fis, &fv);
268:       ISDestroy(&fis);
269:       DMDestroy(&fdm);
270:     }
271:   }
272:   return(0);
273: }

275: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
276: {
277:   DM                      dm;
278:   Vec                     locv;
279:   const char              *name;
280:   PetscSection            section;
281:   PetscInt                pStart, pEnd;
282:   PetscInt                numFields;
283:   PetscViewerVTKFieldType ft;
284:   PetscErrorCode          ierr;

287:   VecGetDM(v, &dm);
288:   DMCreateLocalVector(dm, &locv); /* VTK viewer requires exclusive ownership of the vector */
289:   PetscObjectGetName((PetscObject) v, &name);
290:   PetscObjectSetName((PetscObject) locv, name);
291:   VecCopy(v, locv);
292:   DMGetLocalSection(dm, &section);
293:   PetscSectionGetNumFields(section, &numFields);
294:   if (!numFields) {
295:     DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
296:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv);
297:   } else {
298:     PetscInt f;

300:     for (f = 0; f < numFields; f++) {
301:       DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft);
302:       if (ft == PETSC_VTK_INVALID) continue;
303:       PetscObjectReference((PetscObject)locv);
304:       PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv);
305:     }
306:     VecDestroy(&locv);
307:   }
308:   return(0);
309: }

311: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
312: {
313:   DM             dm;
314:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

318:   VecGetDM(v, &dm);
319:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
320:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
321:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
322:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
323:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
324:   if (isvtk || ishdf5 || isdraw || isglvis) {
325:     PetscInt    i,numFields;
326:     PetscObject fe;
327:     PetscBool   fem = PETSC_FALSE;
328:     Vec         locv = v;
329:     const char  *name;
330:     PetscInt    step;
331:     PetscReal   time;

333:     DMGetNumFields(dm, &numFields);
334:     for (i=0; i<numFields; i++) {
335:       DMGetField(dm, i, NULL, &fe);
336:       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
337:     }
338:     if (fem) {
339:       DMGetLocalVector(dm, &locv);
340:       PetscObjectGetName((PetscObject) v, &name);
341:       PetscObjectSetName((PetscObject) locv, name);
342:       VecCopy(v, locv);
343:       DMGetOutputSequenceNumber(dm, NULL, &time);
344:       DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
345:     }
346:     if (isvtk) {
347:       VecView_Plex_Local_VTK(locv, viewer);
348:     } else if (ishdf5) {
349: #if defined(PETSC_HAVE_HDF5)
350:       VecView_Plex_Local_HDF5_Internal(locv, viewer);
351: #else
352:       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
353: #endif
354:     } else if (isdraw) {
355:       VecView_Plex_Local_Draw(locv, viewer);
356:     } else if (isglvis) {
357:       DMGetOutputSequenceNumber(dm, &step, NULL);
358:       PetscViewerGLVisSetSnapId(viewer, step);
359:       VecView_GLVis(locv, viewer);
360:     }
361:     if (fem) {DMRestoreLocalVector(dm, &locv);}
362:   } else {
363:     PetscBool isseq;

365:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
366:     if (isseq) {VecView_Seq(v, viewer);}
367:     else       {VecView_MPI(v, viewer);}
368:   }
369:   return(0);
370: }

372: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
373: {
374:   DM             dm;
375:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

379:   VecGetDM(v, &dm);
380:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
381:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
382:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
383:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
384:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
385:   if (isvtk || isdraw || isglvis) {
386:     Vec         locv;
387:     const char *name;

389:     DMGetLocalVector(dm, &locv);
390:     PetscObjectGetName((PetscObject) v, &name);
391:     PetscObjectSetName((PetscObject) locv, name);
392:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
393:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
394:     VecView_Plex_Local(locv, viewer);
395:     DMRestoreLocalVector(dm, &locv);
396:   } else if (ishdf5) {
397: #if defined(PETSC_HAVE_HDF5)
398:     VecView_Plex_HDF5_Internal(v, viewer);
399: #else
400:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
401: #endif
402:   } else {
403:     PetscBool isseq;

405:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
406:     if (isseq) {VecView_Seq(v, viewer);}
407:     else       {VecView_MPI(v, viewer);}
408:   }
409:   return(0);
410: }

412: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
413: {
414:   DM                dm;
415:   MPI_Comm          comm;
416:   PetscViewerFormat format;
417:   Vec               v;
418:   PetscBool         isvtk, ishdf5;
419:   PetscErrorCode    ierr;

422:   VecGetDM(originalv, &dm);
423:   PetscObjectGetComm((PetscObject) originalv, &comm);
424:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
425:   PetscViewerGetFormat(viewer, &format);
426:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
427:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
428:   if (format == PETSC_VIEWER_NATIVE) {
429:     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
430:     /* this need a better fix */
431:     if (dm->useNatural) {
432:       if (dm->sfNatural) {
433:         const char *vecname;
434:         PetscInt    n, nroots;

436:         VecGetLocalSize(originalv, &n);
437:         PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
438:         if (n == nroots) {
439:           DMGetGlobalVector(dm, &v);
440:           DMPlexGlobalToNaturalBegin(dm, originalv, v);
441:           DMPlexGlobalToNaturalEnd(dm, originalv, v);
442:           PetscObjectGetName((PetscObject) originalv, &vecname);
443:           PetscObjectSetName((PetscObject) v, vecname);
444:         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
445:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
446:     } else v = originalv;
447:   } else v = originalv;

449:   if (ishdf5) {
450: #if defined(PETSC_HAVE_HDF5)
451:     VecView_Plex_HDF5_Native_Internal(v, viewer);
452: #else
453:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
454: #endif
455:   } else if (isvtk) {
456:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
457:   } else {
458:     PetscBool isseq;

460:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
461:     if (isseq) {VecView_Seq(v, viewer);}
462:     else       {VecView_MPI(v, viewer);}
463:   }
464:   if (v != originalv) {DMRestoreGlobalVector(dm, &v);}
465:   return(0);
466: }

468: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
469: {
470:   DM             dm;
471:   PetscBool      ishdf5;

475:   VecGetDM(v, &dm);
476:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
477:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
478:   if (ishdf5) {
479:     DM          dmBC;
480:     Vec         gv;
481:     const char *name;

483:     DMGetOutputDM(dm, &dmBC);
484:     DMGetGlobalVector(dmBC, &gv);
485:     PetscObjectGetName((PetscObject) v, &name);
486:     PetscObjectSetName((PetscObject) gv, name);
487:     VecLoad_Default(gv, viewer);
488:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
489:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
490:     DMRestoreGlobalVector(dmBC, &gv);
491:   } else {
492:     VecLoad_Default(v, viewer);
493:   }
494:   return(0);
495: }

497: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
498: {
499:   DM             dm;
500:   PetscBool      ishdf5;

504:   VecGetDM(v, &dm);
505:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
506:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
507:   if (ishdf5) {
508: #if defined(PETSC_HAVE_HDF5)
509:     VecLoad_Plex_HDF5_Internal(v, viewer);
510: #else
511:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
512: #endif
513:   } else {
514:     VecLoad_Default(v, viewer);
515:   }
516:   return(0);
517: }

519: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
520: {
521:   DM                dm;
522:   PetscViewerFormat format;
523:   PetscBool         ishdf5;
524:   PetscErrorCode    ierr;

527:   VecGetDM(originalv, &dm);
528:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
529:   PetscViewerGetFormat(viewer, &format);
530:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
531:   if (format == PETSC_VIEWER_NATIVE) {
532:     if (dm->useNatural) {
533:       if (dm->sfNatural) {
534:         if (ishdf5) {
535: #if defined(PETSC_HAVE_HDF5)
536:           Vec         v;
537:           const char *vecname;

539:           DMGetGlobalVector(dm, &v);
540:           PetscObjectGetName((PetscObject) originalv, &vecname);
541:           PetscObjectSetName((PetscObject) v, vecname);
542:           VecLoad_Plex_HDF5_Native_Internal(v, viewer);
543:           DMPlexNaturalToGlobalBegin(dm, v, originalv);
544:           DMPlexNaturalToGlobalEnd(dm, v, originalv);
545:           DMRestoreGlobalVector(dm, &v);
546: #else
547:           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
548: #endif
549:         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
550:       }
551:     } else {
552:       VecLoad_Default(originalv, viewer);
553:     }
554:   }
555:   return(0);
556: }

558: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
559: {
560:   PetscSection       coordSection;
561:   Vec                coordinates;
562:   DMLabel            depthLabel, celltypeLabel;
563:   const char        *name[4];
564:   const PetscScalar *a;
565:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
566:   PetscErrorCode     ierr;

569:   DMGetDimension(dm, &dim);
570:   DMGetCoordinatesLocal(dm, &coordinates);
571:   DMGetCoordinateSection(dm, &coordSection);
572:   DMPlexGetDepthLabel(dm, &depthLabel);
573:   DMPlexGetCellTypeLabel(dm, &celltypeLabel);
574:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
575:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
576:   VecGetArrayRead(coordinates, &a);
577:   name[0]     = "vertex";
578:   name[1]     = "edge";
579:   name[dim-1] = "face";
580:   name[dim]   = "cell";
581:   for (c = cStart; c < cEnd; ++c) {
582:     PetscInt *closure = NULL;
583:     PetscInt  closureSize, cl, ct;

585:     DMLabelGetValue(celltypeLabel, c, &ct);
586:     PetscViewerASCIIPrintf(viewer, "Geometry for cell %D polytope type %s:\n", c, DMPolytopeTypes[ct]);
587:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
588:     PetscViewerASCIIPushTab(viewer);
589:     for (cl = 0; cl < closureSize*2; cl += 2) {
590:       PetscInt point = closure[cl], depth, dof, off, d, p;

592:       if ((point < pStart) || (point >= pEnd)) continue;
593:       PetscSectionGetDof(coordSection, point, &dof);
594:       if (!dof) continue;
595:       DMLabelGetValue(depthLabel, point, &depth);
596:       PetscSectionGetOffset(coordSection, point, &off);
597:       PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
598:       for (p = 0; p < dof/dim; ++p) {
599:         PetscViewerASCIIPrintf(viewer, " (");
600:         for (d = 0; d < dim; ++d) {
601:           if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
602:           PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));
603:         }
604:         PetscViewerASCIIPrintf(viewer, ")");
605:       }
606:       PetscViewerASCIIPrintf(viewer, "\n");
607:     }
608:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
609:     PetscViewerASCIIPopTab(viewer);
610:   }
611:   VecRestoreArrayRead(coordinates, &a);
612:   return(0);
613: }

615: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
616: {
617:   DM_Plex          *mesh = (DM_Plex*) dm->data;
618:   DM                cdm;
619:   DMLabel           markers;
620:   PetscSection      coordSection;
621:   Vec               coordinates;
622:   PetscViewerFormat format;
623:   PetscErrorCode    ierr;

626:   DMGetCoordinateDM(dm, &cdm);
627:   DMGetLocalSection(cdm, &coordSection);
628:   DMGetCoordinatesLocal(dm, &coordinates);
629:   PetscViewerGetFormat(viewer, &format);
630:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
631:     const char *name;
632:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
633:     PetscInt    pStart, pEnd, p;
634:     PetscMPIInt rank, size;

636:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
637:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
638:     PetscObjectGetName((PetscObject) dm, &name);
639:     DMPlexGetChart(dm, &pStart, &pEnd);
640:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
641:     DMGetDimension(dm, &dim);
642:     DMPlexGetVTKCellHeight(dm, &cellHeight);
643:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
644:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
645:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
646:     PetscViewerASCIIPrintf(viewer, "Supports:\n", name);
647:     PetscViewerASCIIPushSynchronized(viewer);
648:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);
649:     for (p = pStart; p < pEnd; ++p) {
650:       PetscInt dof, off, s;

652:       PetscSectionGetDof(mesh->supportSection, p, &dof);
653:       PetscSectionGetOffset(mesh->supportSection, p, &off);
654:       for (s = off; s < off+dof; ++s) {
655:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
656:       }
657:     }
658:     PetscViewerFlush(viewer);
659:     PetscViewerASCIIPrintf(viewer, "Cones:\n", name);
660:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);
661:     for (p = pStart; p < pEnd; ++p) {
662:       PetscInt dof, off, c;

664:       PetscSectionGetDof(mesh->coneSection, p, &dof);
665:       PetscSectionGetOffset(mesh->coneSection, p, &off);
666:       for (c = off; c < off+dof; ++c) {
667:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
668:       }
669:     }
670:     PetscViewerFlush(viewer);
671:     PetscViewerASCIIPopSynchronized(viewer);
672:     if (coordSection && coordinates) {
673:       PetscSectionVecView(coordSection, coordinates, viewer);
674:     }
675:     DMGetLabel(dm, "marker", &markers);
676:     if (markers) {DMLabelView(markers,viewer);}
677:     if (size > 1) {
678:       PetscSF sf;

680:       DMGetPointSF(dm, &sf);
681:       PetscSFView(sf, viewer);
682:     }
683:     PetscViewerFlush(viewer);
684:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
685:     const char  *name, *color;
686:     const char  *defcolors[3]  = {"gray", "orange", "green"};
687:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
688:     char         lname[PETSC_MAX_PATH_LEN];
689:     PetscReal    scale         = 2.0;
690:     PetscReal    tikzscale     = 1.0;
691:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
692:     double       tcoords[3];
693:     PetscScalar *coords;
694:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
695:     PetscMPIInt  rank, size;
696:     char         **names, **colors, **lcolors;
697:     PetscBool    plotEdges, flg, lflg;
698:     PetscBT      wp = NULL;
699:     PetscInt     pEnd, pStart;

701:     DMGetDimension(dm, &dim);
702:     DMPlexGetDepth(dm, &depth);
703:     DMGetNumLabels(dm, &numLabels);
704:     numLabels  = PetscMax(numLabels, 10);
705:     numColors  = 10;
706:     numLColors = 10;
707:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
708:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
709:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);
710:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
711:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
712:     if (!useLabels) numLabels = 0;
713:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
714:     if (!useColors) {
715:       numColors = 3;
716:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
717:     }
718:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
719:     if (!useColors) {
720:       numLColors = 4;
721:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
722:     }
723:     PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, PETSC_MAX_PATH_LEN, &lflg);
724:     plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3);
725:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);
726:     if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
727:     if (depth < dim) plotEdges = PETSC_FALSE;

729:     /* filter points with labelvalue != labeldefaultvalue */
730:     DMPlexGetChart(dm, &pStart, &pEnd);
731:     if (lflg) {
732:       DMLabel lbl;

734:       DMGetLabel(dm, lname, &lbl);
735:       if (lbl) {
736:         PetscInt val, defval;

738:         DMLabelGetDefaultValue(lbl, &defval);
739:         PetscBTCreate(pEnd-pStart, &wp);
740:         for (c = pStart;  c < pEnd; c++) {
741:           PetscInt *closure = NULL;
742:           PetscInt  closureSize;

744:           DMLabelGetValue(lbl, c, &val);
745:           if (val == defval) continue;

747:           DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
748:           for (p = 0; p < closureSize*2; p += 2) {
749:             PetscBTSet(wp, closure[p] - pStart);
750:           }
751:           DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
752:         }
753:       }
754:     }

756:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
757:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
758:     PetscObjectGetName((PetscObject) dm, &name);
759:     PetscViewerASCIIPrintf(viewer, "\
760: \\documentclass[tikz]{standalone}\n\n\
761: \\usepackage{pgflibraryshapes}\n\
762: \\usetikzlibrary{backgrounds}\n\
763: \\usetikzlibrary{arrows}\n\
764: \\begin{document}\n");
765:     if (size > 1) {
766:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
767:       for (p = 0; p < size; ++p) {
768:         if (p > 0 && p == size-1) {
769:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
770:         } else if (p > 0) {
771:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
772:         }
773:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
774:       }
775:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
776:     }
777:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);

779:     /* Plot vertices */
780:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
781:     VecGetArray(coordinates, &coords);
782:     PetscViewerASCIIPushSynchronized(viewer);
783:     for (v = vStart; v < vEnd; ++v) {
784:       PetscInt  off, dof, d;
785:       PetscBool isLabeled = PETSC_FALSE;

787:       if (wp && !PetscBTLookup(wp,v - pStart)) continue;
788:       PetscSectionGetDof(coordSection, v, &dof);
789:       PetscSectionGetOffset(coordSection, v, &off);
790:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
791:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
792:       for (d = 0; d < dof; ++d) {
793:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
794:         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
795:       }
796:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
797:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
798:       for (d = 0; d < dof; ++d) {
799:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
800:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);
801:       }
802:       color = colors[rank%numColors];
803:       for (l = 0; l < numLabels; ++l) {
804:         PetscInt val;
805:         DMGetLabelValue(dm, names[l], v, &val);
806:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
807:       }
808:       if (useNumbers) {
809:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
810:       } else {
811:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
812:       }
813:     }
814:     VecRestoreArray(coordinates, &coords);
815:     PetscViewerFlush(viewer);
816:     /* Plot cells */
817:     DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
818:     DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
819:     if (dim == 3 || !useNumbers) {
820:       for (e = eStart; e < eEnd; ++e) {
821:         const PetscInt *cone;

823:         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
824:         color = colors[rank%numColors];
825:         for (l = 0; l < numLabels; ++l) {
826:           PetscInt val;
827:           DMGetLabelValue(dm, names[l], e, &val);
828:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
829:         }
830:         DMPlexGetCone(dm, e, &cone);
831:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
832:       }
833:     } else {
834:       for (c = cStart; c < cEnd; ++c) {
835:         PetscInt *closure = NULL;
836:         PetscInt  closureSize, firstPoint = -1;

838:         if (wp && !PetscBTLookup(wp,c - pStart)) continue;
839:         DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
840:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
841:         for (p = 0; p < closureSize*2; p += 2) {
842:           const PetscInt point = closure[p];

844:           if ((point < vStart) || (point >= vEnd)) continue;
845:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
846:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
847:           if (firstPoint < 0) firstPoint = point;
848:         }
849:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
850:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
851:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
852:       }
853:     }
854:     VecGetArray(coordinates, &coords);
855:     for (c = cStart; c < cEnd; ++c) {
856:       double    ccoords[3] = {0.0, 0.0, 0.0};
857:       PetscBool isLabeled  = PETSC_FALSE;
858:       PetscInt *closure    = NULL;
859:       PetscInt  closureSize, dof, d, n = 0;

861:       if (wp && !PetscBTLookup(wp,c - pStart)) continue;
862:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
863:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
864:       for (p = 0; p < closureSize*2; p += 2) {
865:         const PetscInt point = closure[p];
866:         PetscInt       off;

868:         if ((point < vStart) || (point >= vEnd)) continue;
869:         PetscSectionGetDof(coordSection, point, &dof);
870:         PetscSectionGetOffset(coordSection, point, &off);
871:         for (d = 0; d < dof; ++d) {
872:           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
873:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
874:         }
875:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
876:         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
877:         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
878:         ++n;
879:       }
880:       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
881:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
882:       for (d = 0; d < dof; ++d) {
883:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
884:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);
885:       }
886:       color = colors[rank%numColors];
887:       for (l = 0; l < numLabels; ++l) {
888:         PetscInt val;
889:         DMGetLabelValue(dm, names[l], c, &val);
890:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
891:       }
892:       if (useNumbers) {
893:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);
894:       } else {
895:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);
896:       }
897:     }
898:     VecRestoreArray(coordinates, &coords);
899:     /* Plot edges */
900:     if (plotEdges) {
901:       VecGetArray(coordinates, &coords);
902:       PetscViewerASCIIPrintf(viewer, "\\path\n");
903:       for (e = eStart; e < eEnd; ++e) {
904:         const PetscInt *cone;
905:         PetscInt        coneSize, offA, offB, dof, d;

907:         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
908:         DMPlexGetConeSize(dm, e, &coneSize);
909:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
910:         DMPlexGetCone(dm, e, &cone);
911:         PetscSectionGetDof(coordSection, cone[0], &dof);
912:         PetscSectionGetOffset(coordSection, cone[0], &offA);
913:         PetscSectionGetOffset(coordSection, cone[1], &offB);
914:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
915:         for (d = 0; d < dof; ++d) {
916:           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
917:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
918:         }
919:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
920:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
921:         for (d = 0; d < dof; ++d) {
922:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
923:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
924:         }
925:         color = colors[rank%numColors];
926:         for (l = 0; l < numLabels; ++l) {
927:           PetscInt val;
928:           DMGetLabelValue(dm, names[l], v, &val);
929:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
930:         }
931:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
932:       }
933:       VecRestoreArray(coordinates, &coords);
934:       PetscViewerFlush(viewer);
935:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
936:     }
937:     PetscViewerFlush(viewer);
938:     PetscViewerASCIIPopSynchronized(viewer);
939:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
940:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
941:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
942:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
943:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
944:     PetscFree3(names, colors, lcolors);
945:     PetscBTDestroy(&wp);
946:   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
947:     Vec                    cown,acown;
948:     VecScatter             sct;
949:     ISLocalToGlobalMapping g2l;
950:     IS                     gid,acis;
951:     MPI_Comm               comm,ncomm = MPI_COMM_NULL;
952:     MPI_Group              ggroup,ngroup;
953:     PetscScalar            *array,nid;
954:     const PetscInt         *idxs;
955:     PetscInt               *idxs2,*start,*adjacency,*work;
956:     PetscInt64             lm[3],gm[3];
957:     PetscInt               i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
958:     PetscMPIInt            d1,d2,rank;

960:     PetscObjectGetComm((PetscObject)dm,&comm);
961:     MPI_Comm_rank(comm,&rank);
962: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
963:     MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);
964: #endif
965:     if (ncomm != MPI_COMM_NULL) {
966:       MPI_Comm_group(comm,&ggroup);
967:       MPI_Comm_group(ncomm,&ngroup);
968:       d1   = 0;
969:       MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);
970:       nid  = d2;
971:       MPI_Group_free(&ggroup);
972:       MPI_Group_free(&ngroup);
973:       MPI_Comm_free(&ncomm);
974:     } else nid = 0.0;

976:     /* Get connectivity */
977:     DMPlexGetVTKCellHeight(dm,&cellHeight);
978:     DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);

980:     /* filter overlapped local cells */
981:     DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);
982:     ISGetIndices(gid,&idxs);
983:     ISGetLocalSize(gid,&cum);
984:     PetscMalloc1(cum,&idxs2);
985:     for (c = cStart, cum = 0; c < cEnd; c++) {
986:       if (idxs[c-cStart] < 0) continue;
987:       idxs2[cum++] = idxs[c-cStart];
988:     }
989:     ISRestoreIndices(gid,&idxs);
990:     if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum);
991:     ISDestroy(&gid);
992:     ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);

994:     /* support for node-aware cell locality */
995:     ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);
996:     VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);
997:     VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);
998:     VecGetArray(cown,&array);
999:     for (c = 0; c < numVertices; c++) array[c] = nid;
1000:     VecRestoreArray(cown,&array);
1001:     VecScatterCreate(cown,acis,acown,NULL,&sct);
1002:     VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);
1003:     VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);
1004:     ISDestroy(&acis);
1005:     VecScatterDestroy(&sct);
1006:     VecDestroy(&cown);

1008:     /* compute edgeCut */
1009:     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
1010:     PetscMalloc1(cum,&work);
1011:     ISLocalToGlobalMappingCreateIS(gid,&g2l);
1012:     ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);
1013:     ISDestroy(&gid);
1014:     VecGetArray(acown,&array);
1015:     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1016:       PetscInt totl;

1018:       totl = start[c+1]-start[c];
1019:       ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);
1020:       for (i = 0; i < totl; i++) {
1021:         if (work[i] < 0) {
1022:           ect  += 1;
1023:           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1024:         }
1025:       }
1026:     }
1027:     PetscFree(work);
1028:     VecRestoreArray(acown,&array);
1029:     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
1030:     lm[1] = -numVertices;
1031:     MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);
1032:     PetscViewerASCIIPrintf(viewer,"  Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);
1033:     lm[0] = ect; /* edgeCut */
1034:     lm[1] = ectn; /* node-aware edgeCut */
1035:     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1036:     MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);
1037:     PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);
1038: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1039:     PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.);
1040: #else
1041:     PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);
1042: #endif
1043:     ISLocalToGlobalMappingDestroy(&g2l);
1044:     PetscFree(start);
1045:     PetscFree(adjacency);
1046:     VecDestroy(&acown);
1047:   } else {
1048:     MPI_Comm    comm;
1049:     PetscInt   *sizes, *hybsizes, *ghostsizes;
1050:     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
1051:     PetscInt    pStart, pEnd, p, gcStart, gcEnd, gcNum;
1052:     PetscInt    numLabels, l;
1053:     const char *name;
1054:     PetscMPIInt size;

1056:     PetscObjectGetComm((PetscObject)dm,&comm);
1057:     MPI_Comm_size(comm, &size);
1058:     DMGetDimension(dm, &dim);
1059:     DMPlexGetVTKCellHeight(dm, &cellHeight);
1060:     PetscObjectGetName((PetscObject) dm, &name);
1061:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
1062:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
1063:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
1064:     DMPlexGetDepth(dm, &locDepth);
1065:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
1066:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);
1067:     DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);
1068:     gcNum = gcEnd - gcStart;
1069:     PetscCalloc3(size,&sizes,size,&hybsizes,size,&ghostsizes);
1070:     if (depth == 1) {
1071:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
1072:       pEnd = pEnd - pStart;
1073:       pMax[0] -= pStart;
1074:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1075:       MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1076:       MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);
1077:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
1078:       for (p = 0; p < size; ++p) {
1079:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1080:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1081:       }
1082:       PetscViewerASCIIPrintf(viewer, "\n");
1083:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
1084:       pEnd = pEnd - pStart;
1085:       pMax[depth] -= pStart;
1086:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1087:       MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1088:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
1089:       for (p = 0; p < size; ++p) {
1090:         PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);
1091:         if (hybsizes[p] >= 0)   {PetscViewerASCIIPrintf(viewer, " (%D)", sizes[p] - hybsizes[p]);}
1092:         if (ghostsizes[p] > 0) {PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);}
1093:       }
1094:       PetscViewerASCIIPrintf(viewer, "\n");
1095:     } else {
1096:       PetscMPIInt rank;
1097:       MPI_Comm_rank(comm, &rank);
1098:       for (d = 0; d <= dim; d++) {
1099:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
1100:         pEnd    -= pStart;
1101:         pMax[d] -= pStart;
1102:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1103:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1104:         if (d == dim) {MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);}
1105:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
1106:         for (p = 0; p < size; ++p) {
1107:           if (!rank) {
1108:             PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);
1109:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " (%D)", sizes[p] - hybsizes[p]);}
1110:             if (d == dim && ghostsizes[p] > 0) {PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);}
1111:           }
1112:         }
1113:         PetscViewerASCIIPrintf(viewer, "\n");
1114:       }
1115:     }
1116:     PetscFree3(sizes,hybsizes,ghostsizes);
1117:     DMGetNumLabels(dm, &numLabels);
1118:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
1119:     for (l = 0; l < numLabels; ++l) {
1120:       DMLabel         label;
1121:       const char     *name;
1122:       IS              valueIS;
1123:       const PetscInt *values;
1124:       PetscInt        numValues, v;

1126:       DMGetLabelName(dm, l, &name);
1127:       DMGetLabel(dm, name, &label);
1128:       DMLabelGetNumValues(label, &numValues);
1129:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
1130:       DMLabelGetValueIS(label, &valueIS);
1131:       ISGetIndices(valueIS, &values);
1132:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
1133:       for (v = 0; v < numValues; ++v) {
1134:         PetscInt size;

1136:         DMLabelGetStratumSize(label, values[v], &size);
1137:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
1138:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
1139:       }
1140:       PetscViewerASCIIPrintf(viewer, ")\n");
1141:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
1142:       ISRestoreIndices(valueIS, &values);
1143:       ISDestroy(&valueIS);
1144:     }
1145:     /* If no fields are specified, people do not want to see adjacency */
1146:     if (dm->Nf) {
1147:       PetscInt f;

1149:       for (f = 0; f < dm->Nf; ++f) {
1150:         const char *name;

1152:         PetscObjectGetName(dm->fields[f].disc, &name);
1153:         if (numLabels) {PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);}
1154:         PetscViewerASCIIPushTab(viewer);
1155:         if (dm->fields[f].label) {DMLabelView(dm->fields[f].label, viewer);}
1156:         if (dm->fields[f].adjacency[0]) {
1157:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");}
1158:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");}
1159:         } else {
1160:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");}
1161:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");}
1162:         }
1163:         PetscViewerASCIIPopTab(viewer);
1164:       }
1165:     }
1166:     DMGetCoarseDM(dm, &cdm);
1167:     if (cdm) {
1168:       PetscViewerASCIIPushTab(viewer);
1169:       DMPlexView_Ascii(cdm, viewer);
1170:       PetscViewerASCIIPopTab(viewer);
1171:     }
1172:   }
1173:   return(0);
1174: }

1176: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1177: {
1178:   PetscDraw          draw;
1179:   DM                 cdm;
1180:   PetscSection       coordSection;
1181:   Vec                coordinates;
1182:   const PetscScalar *coords;
1183:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1184:   PetscBool          isnull;
1185:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
1186:   PetscMPIInt        rank;
1187:   PetscErrorCode     ierr;

1190:   DMGetCoordinateDim(dm, &dim);
1191:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1192:   DMGetCoordinateDM(dm, &cdm);
1193:   DMGetLocalSection(cdm, &coordSection);
1194:   DMGetCoordinatesLocal(dm, &coordinates);
1195:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1196:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

1198:   PetscViewerDrawGetDraw(viewer, 0, &draw);
1199:   PetscDrawIsNull(draw, &isnull);
1200:   if (isnull) return(0);
1201:   PetscDrawSetTitle(draw, "Mesh");

1203:   VecGetLocalSize(coordinates, &N);
1204:   VecGetArrayRead(coordinates, &coords);
1205:   for (c = 0; c < N; c += dim) {
1206:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1207:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1208:   }
1209:   VecRestoreArrayRead(coordinates, &coords);
1210:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1211:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1212:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1213:   PetscDrawClear(draw);

1215:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1216:   for (c = cStart; c < cEnd; ++c) {
1217:     PetscScalar   *coords = NULL;
1218:     DMPolytopeType ct;
1219:     PetscInt       numCoords;

1221:     DMPlexGetCellType(dm, c, &ct);
1222:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1223:     switch (ct) {
1224:     case DM_POLYTOPE_TRIANGLE:
1225:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1226:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1227:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1228:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1229:       break;
1230:     case DM_POLYTOPE_QUADRILATERAL:
1231:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1232:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1233:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1234:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1235:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]),
1236:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1237:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1238:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1239:       break;
1240:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1241:     }
1242:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1243:   }
1244:   for (c = cStart; c < cEnd; ++c) {
1245:     PetscScalar   *coords = NULL;
1246:     DMPolytopeType ct;
1247:     PetscInt       numCoords;

1249:     DMPlexGetCellType(dm, c, &ct);
1250:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1251:     switch (ct) {
1252:     case DM_POLYTOPE_TRIANGLE:
1253:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1254:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1255:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1256:       break;
1257:     case DM_POLYTOPE_QUADRILATERAL:
1258:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1259:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1260:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
1261:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1262:       break;
1263:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1264:     }
1265:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1266:   }
1267:   PetscDrawFlush(draw);
1268:   PetscDrawPause(draw);
1269:   PetscDrawSave(draw);
1270:   return(0);
1271: }

1273: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1274: {
1275:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1276:   char           name[PETSC_MAX_PATH_LEN];

1282:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
1283:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
1284:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
1285:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
1286:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
1287:   if (iascii) {
1288:     PetscViewerFormat format;
1289:     PetscViewerGetFormat(viewer, &format);
1290:     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1291:       DMPlexView_GLVis(dm, viewer);
1292:     } else {
1293:       DMPlexView_Ascii(dm, viewer);
1294:     }
1295:   } else if (ishdf5) {
1296: #if defined(PETSC_HAVE_HDF5)
1297:     DMPlexView_HDF5_Internal(dm, viewer);
1298: #else
1299:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1300: #endif
1301:   } else if (isvtk) {
1302:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
1303:   } else if (isdraw) {
1304:     DMPlexView_Draw(dm, viewer);
1305:   } else if (isglvis) {
1306:     DMPlexView_GLVis(dm, viewer);
1307:   } else {
1308:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1309:   }
1310:   /* Optionally view the partition */
1311:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1312:   if (flg) {
1313:     Vec ranks;
1314:     DMPlexCreateRankField(dm, &ranks);
1315:     VecView(ranks, viewer);
1316:     VecDestroy(&ranks);
1317:   }
1318:   /* Optionally view a label */
1319:   PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, PETSC_MAX_PATH_LEN, &flg);
1320:   if (flg) {
1321:     DMLabel label;
1322:     Vec     val;

1324:     DMGetLabel(dm, name, &label);
1325:     if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1326:     DMPlexCreateLabelField(dm, label, &val);
1327:     VecView(val, viewer);
1328:     VecDestroy(&val);
1329:   }
1330:   return(0);
1331: }

1333: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1334: {
1335:   PetscBool      ishdf5;

1341:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
1342:   if (ishdf5) {
1343: #if defined(PETSC_HAVE_HDF5)
1344:     PetscViewerFormat format;
1345:     PetscViewerGetFormat(viewer, &format);
1346:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1347:       DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
1348:     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1349:       DMPlexLoad_HDF5_Internal(dm, viewer);
1350:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1351: #else
1352:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1353: #endif
1354:   } else {
1355:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1356:   }
1357:   return(0);
1358: }

1360: PetscErrorCode DMDestroy_Plex(DM dm)
1361: {
1362:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1366:   PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1367:   PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1368:   PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);
1369:   if (--mesh->refct > 0) return(0);
1370:   PetscSectionDestroy(&mesh->coneSection);
1371:   PetscFree(mesh->cones);
1372:   PetscFree(mesh->coneOrientations);
1373:   PetscSectionDestroy(&mesh->supportSection);
1374:   PetscSectionDestroy(&mesh->subdomainSection);
1375:   PetscFree(mesh->supports);
1376:   PetscFree(mesh->facesTmp);
1377:   PetscFree(mesh->tetgenOpts);
1378:   PetscFree(mesh->triangleOpts);
1379:   PetscPartitionerDestroy(&mesh->partitioner);
1380:   DMLabelDestroy(&mesh->subpointMap);
1381:   ISDestroy(&mesh->globalVertexNumbers);
1382:   ISDestroy(&mesh->globalCellNumbers);
1383:   PetscSectionDestroy(&mesh->anchorSection);
1384:   ISDestroy(&mesh->anchorIS);
1385:   PetscSectionDestroy(&mesh->parentSection);
1386:   PetscFree(mesh->parents);
1387:   PetscFree(mesh->childIDs);
1388:   PetscSectionDestroy(&mesh->childSection);
1389:   PetscFree(mesh->children);
1390:   DMDestroy(&mesh->referenceTree);
1391:   PetscGridHashDestroy(&mesh->lbox);
1392:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1393:   PetscFree(mesh);
1394:   return(0);
1395: }

1397: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1398: {
1399:   PetscSection           sectionGlobal;
1400:   PetscInt               bs = -1, mbs;
1401:   PetscInt               localSize;
1402:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1403:   PetscErrorCode         ierr;
1404:   MatType                mtype;
1405:   ISLocalToGlobalMapping ltog;

1408:   MatInitializePackage();
1409:   mtype = dm->mattype;
1410:   DMGetGlobalSection(dm, &sectionGlobal);
1411:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1412:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1413:   MatCreate(PetscObjectComm((PetscObject)dm), J);
1414:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1415:   MatSetType(*J, mtype);
1416:   MatSetFromOptions(*J);
1417:   MatGetBlockSize(*J, &mbs);
1418:   if (mbs > 1) bs = mbs;
1419:   PetscStrcmp(mtype, MATSHELL, &isShell);
1420:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
1421:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1422:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1423:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1424:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1425:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1426:   PetscStrcmp(mtype, MATIS, &isMatIS);
1427:   if (!isShell) {
1428:     PetscSection subSection;
1429:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1430:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1431:     PetscInt     pStart, pEnd, p, dof, cdof;

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

1438:       DMGetLocalSection(dm, &section);
1439:       PetscSectionGetStorageSize(section, &size);
1440:       PetscMalloc1(size,&ltogidx);
1441:       DMPlexGetSubdomainSection(dm, &subSection);
1442:     } else {
1443:       DMGetLocalToGlobalMapping(dm,&ltog);
1444:     }
1445:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1446:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1447:       PetscInt bdof;

1449:       PetscSectionGetDof(sectionGlobal, p, &dof);
1450:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1451:       dof  = dof < 0 ? -(dof+1) : dof;
1452:       bdof = cdof && (dof-cdof) ? 1 : dof;
1453:       if (dof) {
1454:         if (bs < 0)          {bs = bdof;}
1455:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1456:       }
1457:       if (isMatIS) {
1458:         PetscInt loff,c,off;
1459:         PetscSectionGetOffset(subSection, p, &loff);
1460:         PetscSectionGetOffset(sectionGlobal, p, &off);
1461:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1462:       }
1463:     }
1464:     /* Must have same blocksize on all procs (some might have no points) */
1465:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1466:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1467:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1468:     else                            {bs = bsMinMax[0];}
1469:     bs = PetscMax(1,bs);
1470:     if (isMatIS) { /* Must reduce indices by blocksize */
1471:       PetscInt l;

1473:       lsize = lsize/bs;
1474:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] = ltogidx[l*bs]/bs;
1475:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1476:     }
1477:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1478:     if (isMatIS) {
1479:       ISLocalToGlobalMappingDestroy(&ltog);
1480:     }
1481:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1482:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1483:     PetscFree4(dnz, onz, dnzu, onzu);
1484:   }
1485:   MatSetDM(*J, dm);
1486:   return(0);
1487: }

1489: /*@
1490:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1492:   Not collective

1494:   Input Parameter:
1495: . mesh - The DMPlex

1497:   Output Parameters:
1498: . subsection - The subdomain section

1500:   Level: developer

1502: .seealso:
1503: @*/
1504: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1505: {
1506:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1511:   if (!mesh->subdomainSection) {
1512:     PetscSection section;
1513:     PetscSF      sf;

1515:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1516:     DMGetLocalSection(dm,&section);
1517:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1518:     PetscSFDestroy(&sf);
1519:   }
1520:   *subsection = mesh->subdomainSection;
1521:   return(0);
1522: }

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

1527:   Not collective

1529:   Input Parameter:
1530: . mesh - The DMPlex

1532:   Output Parameters:
1533: + pStart - The first mesh point
1534: - pEnd   - The upper bound for mesh points

1536:   Level: beginner

1538: .seealso: DMPlexCreate(), DMPlexSetChart()
1539: @*/
1540: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1541: {
1542:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1547:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1548:   return(0);
1549: }

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

1554:   Not collective

1556:   Input Parameters:
1557: + mesh - The DMPlex
1558: . pStart - The first mesh point
1559: - pEnd   - The upper bound for mesh points

1561:   Output Parameters:

1563:   Level: beginner

1565: .seealso: DMPlexCreate(), DMPlexGetChart()
1566: @*/
1567: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1568: {
1569:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1574:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1575:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1576:   return(0);
1577: }

1579: /*@
1580:   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG

1582:   Not collective

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

1588:   Output Parameter:
1589: . size - The cone size for point p

1591:   Level: beginner

1593: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1594: @*/
1595: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1596: {
1597:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1603:   PetscSectionGetDof(mesh->coneSection, p, size);
1604:   return(0);
1605: }

1607: /*@
1608:   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG

1610:   Not collective

1612:   Input Parameters:
1613: + mesh - The DMPlex
1614: . p - The point, which must lie in the chart set with DMPlexSetChart()
1615: - size - The cone size for point p

1617:   Output Parameter:

1619:   Note:
1620:   This should be called after DMPlexSetChart().

1622:   Level: beginner

1624: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1625: @*/
1626: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1627: {
1628:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1635:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1636:   return(0);
1637: }

1639: /*@
1640:   DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG

1642:   Not collective

1644:   Input Parameters:
1645: + mesh - The DMPlex
1646: . p - The point, which must lie in the chart set with DMPlexSetChart()
1647: - size - The additional cone size for point p

1649:   Output Parameter:

1651:   Note:
1652:   This should be called after DMPlexSetChart().

1654:   Level: beginner

1656: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1657: @*/
1658: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1659: {
1660:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1661:   PetscInt       csize;

1666:   PetscSectionAddDof(mesh->coneSection, p, size);
1667:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1669:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1670:   return(0);
1671: }

1673: /*@C
1674:   DMPlexGetCone - Return the points on the in-edges for this point in the DAG

1676:   Not collective

1678:   Input Parameters:
1679: + dm - The DMPlex
1680: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1685:   Level: beginner

1687:   Fortran Notes:
1688:   Since it returns an array, this routine is only available in Fortran 90, and you must
1689:   include petsc.h90 in your code.
1690:   You must also call DMPlexRestoreCone() after you finish using the returned array.
1691:   DMPlexRestoreCone() is not needed/available in C.

1693: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
1694: @*/
1695: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1696: {
1697:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1698:   PetscInt       off;

1704:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1705:   *cone = &mesh->cones[off];
1706:   return(0);
1707: }

1709: /*@C
1710:   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG

1712:   Not collective

1714:   Input Parameters:
1715: + dm - The DMPlex
1716: - p - The IS of points, which must lie in the chart set with DMPlexSetChart()

1718:   Output Parameter:
1719: + pConesSection - PetscSection describing the layout of pCones
1720: - pCones - An array of points which are on the in-edges for the point set p

1722:   Level: intermediate

1724: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
1725: @*/
1726: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
1727: {
1728:   PetscSection        cs, newcs;
1729:   PetscInt            *cones;
1730:   PetscInt            *newarr=NULL;
1731:   PetscInt            n;
1732:   PetscErrorCode      ierr;

1735:   DMPlexGetCones(dm, &cones);
1736:   DMPlexGetConeSection(dm, &cs);
1737:   PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);
1738:   if (pConesSection) *pConesSection = newcs;
1739:   if (pCones) {
1740:     PetscSectionGetStorageSize(newcs, &n);
1741:     ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);
1742:   }
1743:   return(0);
1744: }

1746: /*@
1747:   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.

1749:   Not collective

1751:   Input Parameters:
1752: + dm - The DMPlex
1753: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()

1755:   Output Parameter:
1756: . expandedPoints - An array of vertices recursively expanded from input points

1758:   Level: advanced

1760:   Notes:
1761:   Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
1762:   There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.

1764: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth()
1765: @*/
1766: PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
1767: {
1768:   IS                  *expandedPointsAll;
1769:   PetscInt            depth;
1770:   PetscErrorCode      ierr;

1776:   DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);
1777:   *expandedPoints = expandedPointsAll[0];
1778:   PetscObjectReference((PetscObject)expandedPointsAll[0]);
1779:   DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);
1780:   return(0);
1781: }

1783: /*@
1784:   DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones).

1786:   Not collective

1788:   Input Parameters:
1789: + dm - The DMPlex
1790: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()

1792:   Output Parameter:
1793: + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
1794: . expandedPoints - (optional) An array of index sets with recursively expanded cones
1795: - sections - (optional) An array of sections which describe mappings from points to their cone points

1797:   Level: advanced

1799:   Notes:
1800:   Like DMPlexGetConeTuple() but recursive.

1802:   Array expandedPoints has size equal to depth. Each expandedPoints[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points.
1803:   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.

1805:   Array section has size equal to depth.  Each PetscSection sections[d] realizes mapping from expandedPoints[d+1] (section points) to expandedPoints[d] (section dofs) as follows:
1806:   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
1807:   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].

1809: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
1810: @*/
1811: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
1812: {
1813:   const PetscInt      *arr0=NULL, *cone=NULL;
1814:   PetscInt            *arr=NULL, *newarr=NULL;
1815:   PetscInt            d, depth_, i, n, newn, cn, co, start, end;
1816:   IS                  *expandedPoints_;
1817:   PetscSection        *sections_;
1818:   PetscErrorCode      ierr;

1826:   ISGetLocalSize(points, &n);
1827:   ISGetIndices(points, &arr0);
1828:   DMPlexGetDepth(dm, &depth_);
1829:   PetscCalloc1(depth_, &expandedPoints_);
1830:   PetscCalloc1(depth_, &sections_);
1831:   arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
1832:   for (d=depth_-1; d>=0; d--) {
1833:     PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]);
1834:     PetscSectionSetChart(sections_[d], 0, n);
1835:     for (i=0; i<n; i++) {
1836:       DMPlexGetDepthStratum(dm, d+1, &start, &end);
1837:       if (arr[i] >= start && arr[i] < end) {
1838:         DMPlexGetConeSize(dm, arr[i], &cn);
1839:         PetscSectionSetDof(sections_[d], i, cn);
1840:       } else {
1841:         PetscSectionSetDof(sections_[d], i, 1);
1842:       }
1843:     }
1844:     PetscSectionSetUp(sections_[d]);
1845:     PetscSectionGetStorageSize(sections_[d], &newn);
1846:     PetscMalloc1(newn, &newarr);
1847:     for (i=0; i<n; i++) {
1848:       PetscSectionGetDof(sections_[d], i, &cn);
1849:       PetscSectionGetOffset(sections_[d], i, &co);
1850:       if (cn > 1) {
1851:         DMPlexGetCone(dm, arr[i], &cone);
1852:         PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));
1853:       } else {
1854:         newarr[co] = arr[i];
1855:       }
1856:     }
1857:     ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);
1858:     arr = newarr;
1859:     n = newn;
1860:   }
1861:   ISRestoreIndices(points, &arr0);
1862:   *depth = depth_;
1863:   if (expandedPoints) *expandedPoints = expandedPoints_;
1864:   else {
1865:     for (d=0; d<depth_; d++) {ISDestroy(&expandedPoints_[d]);}
1866:     PetscFree(expandedPoints_);
1867:   }
1868:   if (sections) *sections = sections_;
1869:   else {
1870:     for (d=0; d<depth_; d++) {PetscSectionDestroy(&sections_[d]);}
1871:     PetscFree(sections_);
1872:   }
1873:   return(0);
1874: }

1876: /*@
1877:   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive

1879:   Not collective

1881:   Input Parameters:
1882: + dm - The DMPlex
1883: - points - The IS of points, which must lie in the chart set with DMPlexSetChart()

1885:   Output Parameter:
1886: + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
1887: . expandedPoints - (optional) An array of recursively expanded cones
1888: - sections - (optional) An array of sections which describe mappings from points to their cone points

1890:   Level: advanced

1892:   Notes:
1893:   See DMPlexGetConeRecursive() for details.

1895: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
1896: @*/
1897: PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
1898: {
1899:   PetscInt            d, depth_;
1900:   PetscErrorCode      ierr;

1903:   DMPlexGetDepth(dm, &depth_);
1904:   if (depth && *depth != depth_) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
1905:   if (depth) *depth = 0;
1906:   if (expandedPoints) {
1907:     for (d=0; d<depth_; d++) {ISDestroy(&((*expandedPoints)[d]));}
1908:     PetscFree(*expandedPoints);
1909:   }
1910:   if (sections)  {
1911:     for (d=0; d<depth_; d++) {PetscSectionDestroy(&((*sections)[d]));}
1912:     PetscFree(*sections);
1913:   }
1914:   return(0);
1915: }

1917: /*@
1918:   DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point

1920:   Not collective

1922:   Input Parameters:
1923: + mesh - The DMPlex
1924: . p - The point, which must lie in the chart set with DMPlexSetChart()
1925: - cone - An array of points which are on the in-edges for point p

1927:   Output Parameter:

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

1932:   Developer Note: Why not call this DMPlexSetCover()

1934:   Level: beginner

1936: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1937: @*/
1938: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1939: {
1940:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1941:   PetscInt       pStart, pEnd;
1942:   PetscInt       dof, off, c;

1947:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1948:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1950:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1951:   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);
1952:   for (c = 0; c < dof; ++c) {
1953:     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);
1954:     mesh->cones[off+c] = cone[c];
1955:   }
1956:   return(0);
1957: }

1959: /*@C
1960:   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG

1962:   Not collective

1964:   Input Parameters:
1965: + mesh - The DMPlex
1966: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1974:   Level: beginner

1976:   Fortran Notes:
1977:   Since it returns an array, this routine is only available in Fortran 90, and you must
1978:   include petsc.h90 in your code.
1979:   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1980:   DMPlexRestoreConeOrientation() is not needed/available in C.

1982: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1983: @*/
1984: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1985: {
1986:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1987:   PetscInt       off;

1992: #if defined(PETSC_USE_DEBUG)
1993:   {
1994:     PetscInt dof;
1995:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1997:   }
1998: #endif
1999:   PetscSectionGetOffset(mesh->coneSection, p, &off);

2001:   *coneOrientation = &mesh->coneOrientations[off];
2002:   return(0);
2003: }

2005: /*@
2006:   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG

2008:   Not collective

2010:   Input Parameters:
2011: + mesh - The DMPlex
2012: . p - The point, which must lie in the chart set with DMPlexSetChart()
2013: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
2014:                     integer giving the prescription for cone traversal. If it is negative, the cone is
2015:                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
2016:                     the index of the cone point on which to start.

2018:   Output Parameter:

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

2023:   Level: beginner

2025: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2026: @*/
2027: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
2028: {
2029:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2030:   PetscInt       pStart, pEnd;
2031:   PetscInt       dof, off, c;

2036:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2037:   PetscSectionGetDof(mesh->coneSection, p, &dof);
2039:   PetscSectionGetOffset(mesh->coneSection, p, &off);
2040:   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);
2041:   for (c = 0; c < dof; ++c) {
2042:     PetscInt cdof, o = coneOrientation[c];

2044:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
2045:     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);
2046:     mesh->coneOrientations[off+c] = o;
2047:   }
2048:   return(0);
2049: }

2051: /*@
2052:   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG

2054:   Not collective

2056:   Input Parameters:
2057: + mesh - The DMPlex
2058: . p - The point, which must lie in the chart set with DMPlexSetChart()
2059: . conePos - The local index in the cone where the point should be put
2060: - conePoint - The mesh point to insert

2062:   Level: beginner

2064: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2065: @*/
2066: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
2067: {
2068:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2069:   PetscInt       pStart, pEnd;
2070:   PetscInt       dof, off;

2075:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2076:   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);
2077:   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);
2078:   PetscSectionGetDof(mesh->coneSection, p, &dof);
2079:   PetscSectionGetOffset(mesh->coneSection, p, &off);
2080:   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);
2081:   mesh->cones[off+conePos] = conePoint;
2082:   return(0);
2083: }

2085: /*@
2086:   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG

2088:   Not collective

2090:   Input Parameters:
2091: + mesh - The DMPlex
2092: . p - The point, which must lie in the chart set with DMPlexSetChart()
2093: . conePos - The local index in the cone where the point should be put
2094: - coneOrientation - The point orientation to insert

2096:   Level: beginner

2098: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2099: @*/
2100: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
2101: {
2102:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2103:   PetscInt       pStart, pEnd;
2104:   PetscInt       dof, off;

2109:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
2110:   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);
2111:   PetscSectionGetDof(mesh->coneSection, p, &dof);
2112:   PetscSectionGetOffset(mesh->coneSection, p, &off);
2113:   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);
2114:   mesh->coneOrientations[off+conePos] = coneOrientation;
2115:   return(0);
2116: }

2118: /*@
2119:   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG

2121:   Not collective

2123:   Input Parameters:
2124: + mesh - The DMPlex
2125: - p - The point, which must lie in the chart set with DMPlexSetChart()

2127:   Output Parameter:
2128: . size - The support size for point p

2130:   Level: beginner

2132: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
2133: @*/
2134: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
2135: {
2136:   DM_Plex       *mesh = (DM_Plex*) dm->data;

2142:   PetscSectionGetDof(mesh->supportSection, p, size);
2143:   return(0);
2144: }

2146: /*@
2147:   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG

2149:   Not collective

2151:   Input Parameters:
2152: + mesh - The DMPlex
2153: . p - The point, which must lie in the chart set with DMPlexSetChart()
2154: - size - The support size for point p

2156:   Output Parameter:

2158:   Note:
2159:   This should be called after DMPlexSetChart().

2161:   Level: beginner

2163: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
2164: @*/
2165: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
2166: {
2167:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

2174:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
2175:   return(0);
2176: }

2178: /*@C
2179:   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG

2181:   Not collective

2183:   Input Parameters:
2184: + mesh - The DMPlex
2185: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

2190:   Level: beginner

2192:   Fortran Notes:
2193:   Since it returns an array, this routine is only available in Fortran 90, and you must
2194:   include petsc.h90 in your code.
2195:   You must also call DMPlexRestoreSupport() after you finish using the returned array.
2196:   DMPlexRestoreSupport() is not needed/available in C.

2198: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2199: @*/
2200: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
2201: {
2202:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2203:   PetscInt       off;

2209:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2210:   *support = &mesh->supports[off];
2211:   return(0);
2212: }

2214: /*@
2215:   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers

2217:   Not collective

2219:   Input Parameters:
2220: + mesh - The DMPlex
2221: . p - The point, which must lie in the chart set with DMPlexSetChart()
2222: - support - An array of points which are on the out-edges for point p

2224:   Output Parameter:

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

2229:   Level: beginner

2231: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
2232: @*/
2233: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
2234: {
2235:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2236:   PetscInt       pStart, pEnd;
2237:   PetscInt       dof, off, c;

2242:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2243:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2245:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2246:   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);
2247:   for (c = 0; c < dof; ++c) {
2248:     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);
2249:     mesh->supports[off+c] = support[c];
2250:   }
2251:   return(0);
2252: }

2254: /*@
2255:   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG

2257:   Not collective

2259:   Input Parameters:
2260: + mesh - The DMPlex
2261: . p - The point, which must lie in the chart set with DMPlexSetChart()
2262: . supportPos - The local index in the cone where the point should be put
2263: - supportPoint - The mesh point to insert

2265:   Level: beginner

2267: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2268: @*/
2269: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
2270: {
2271:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2272:   PetscInt       pStart, pEnd;
2273:   PetscInt       dof, off;

2278:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2279:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2280:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2281:   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);
2282:   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);
2283:   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);
2284:   mesh->supports[off+supportPos] = supportPoint;
2285:   return(0);
2286: }

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

2291:   Not collective

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

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

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

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

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

2312:   Level: beginner

2314: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2315: @*/
2316: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2317: {
2318:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2319:   PetscInt       *closure, *fifo;
2320:   const PetscInt *tmp = NULL, *tmpO = NULL;
2321:   PetscInt        tmpSize, t;
2322:   PetscInt        depth       = 0, maxSize;
2323:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2324:   PetscErrorCode  ierr;

2328:   DMPlexGetDepth(dm, &depth);
2329:   /* This is only 1-level */
2330:   if (useCone) {
2331:     DMPlexGetConeSize(dm, p, &tmpSize);
2332:     DMPlexGetCone(dm, p, &tmp);
2333:     DMPlexGetConeOrientation(dm, p, &tmpO);
2334:   } else {
2335:     DMPlexGetSupportSize(dm, p, &tmpSize);
2336:     DMPlexGetSupport(dm, p, &tmp);
2337:   }
2338:   if (depth == 1) {
2339:     if (*points) {
2340:       closure = *points;
2341:     } else {
2342:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2343:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2344:     }
2345:     closure[0] = p; closure[1] = 0;
2346:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2347:       closure[closureSize]   = tmp[t];
2348:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2349:     }
2350:     if (numPoints) *numPoints = closureSize/2;
2351:     if (points)    *points    = closure;
2352:     return(0);
2353:   }
2354:   {
2355:     PetscInt c, coneSeries, s,supportSeries;

2357:     c = mesh->maxConeSize;
2358:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2359:     s = mesh->maxSupportSize;
2360:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2361:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2362:   }
2363:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2364:   if (*points) {
2365:     closure = *points;
2366:   } else {
2367:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2368:   }
2369:   closure[0] = p; closure[1] = 0;
2370:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2371:     const PetscInt cp = tmp[t];
2372:     const PetscInt co = tmpO ? tmpO[t] : 0;

2374:     closure[closureSize]   = cp;
2375:     closure[closureSize+1] = co;
2376:     fifo[fifoSize]         = cp;
2377:     fifo[fifoSize+1]       = co;
2378:   }
2379:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2380:   while (fifoSize - fifoStart) {
2381:     const PetscInt q   = fifo[fifoStart];
2382:     const PetscInt o   = fifo[fifoStart+1];
2383:     const PetscInt rev = o >= 0 ? 0 : 1;
2384:     const PetscInt off = rev ? -(o+1) : o;

2386:     if (useCone) {
2387:       DMPlexGetConeSize(dm, q, &tmpSize);
2388:       DMPlexGetCone(dm, q, &tmp);
2389:       DMPlexGetConeOrientation(dm, q, &tmpO);
2390:     } else {
2391:       DMPlexGetSupportSize(dm, q, &tmpSize);
2392:       DMPlexGetSupport(dm, q, &tmp);
2393:       tmpO = NULL;
2394:     }
2395:     for (t = 0; t < tmpSize; ++t) {
2396:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2397:       const PetscInt cp = tmp[i];
2398:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2399:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2400:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2401:       PetscInt       co = tmpO ? tmpO[i] : 0;
2402:       PetscInt       c;

2404:       if (rev) {
2405:         PetscInt childSize, coff;
2406:         DMPlexGetConeSize(dm, cp, &childSize);
2407:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2408:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2409:       }
2410:       /* Check for duplicate */
2411:       for (c = 0; c < closureSize; c += 2) {
2412:         if (closure[c] == cp) break;
2413:       }
2414:       if (c == closureSize) {
2415:         closure[closureSize]   = cp;
2416:         closure[closureSize+1] = co;
2417:         fifo[fifoSize]         = cp;
2418:         fifo[fifoSize+1]       = co;
2419:         closureSize           += 2;
2420:         fifoSize              += 2;
2421:       }
2422:     }
2423:     fifoStart += 2;
2424:   }
2425:   if (numPoints) *numPoints = closureSize/2;
2426:   if (points)    *points    = closure;
2427:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2428:   return(0);
2429: }

2431: /*@C
2432:   DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG with a specified initial orientation

2434:   Not collective

2436:   Input Parameters:
2437: + mesh - The DMPlex
2438: . p - The point, which must lie in the chart set with DMPlexSetChart()
2439: . orientation - The orientation of the point
2440: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2441: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

2456:   Level: beginner

2458: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2459: @*/
2460: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2461: {
2462:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2463:   PetscInt       *closure, *fifo;
2464:   const PetscInt *tmp = NULL, *tmpO = NULL;
2465:   PetscInt        tmpSize, t;
2466:   PetscInt        depth       = 0, maxSize;
2467:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2468:   PetscErrorCode  ierr;

2472:   DMPlexGetDepth(dm, &depth);
2473:   /* This is only 1-level */
2474:   if (useCone) {
2475:     DMPlexGetConeSize(dm, p, &tmpSize);
2476:     DMPlexGetCone(dm, p, &tmp);
2477:     DMPlexGetConeOrientation(dm, p, &tmpO);
2478:   } else {
2479:     DMPlexGetSupportSize(dm, p, &tmpSize);
2480:     DMPlexGetSupport(dm, p, &tmp);
2481:   }
2482:   if (depth == 1) {
2483:     if (*points) {
2484:       closure = *points;
2485:     } else {
2486:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2487:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2488:     }
2489:     closure[0] = p; closure[1] = ornt;
2490:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2491:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2492:       closure[closureSize]   = tmp[i];
2493:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2494:     }
2495:     if (numPoints) *numPoints = closureSize/2;
2496:     if (points)    *points    = closure;
2497:     return(0);
2498:   }
2499:   {
2500:     PetscInt c, coneSeries, s,supportSeries;

2502:     c = mesh->maxConeSize;
2503:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2504:     s = mesh->maxSupportSize;
2505:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2506:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2507:   }
2508:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2509:   if (*points) {
2510:     closure = *points;
2511:   } else {
2512:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2513:   }
2514:   closure[0] = p; closure[1] = ornt;
2515:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2516:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2517:     const PetscInt cp = tmp[i];
2518:     PetscInt       co = tmpO ? tmpO[i] : 0;

2520:     if (ornt < 0) {
2521:       PetscInt childSize, coff;
2522:       DMPlexGetConeSize(dm, cp, &childSize);
2523:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2524:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2525:     }
2526:     closure[closureSize]   = cp;
2527:     closure[closureSize+1] = co;
2528:     fifo[fifoSize]         = cp;
2529:     fifo[fifoSize+1]       = co;
2530:   }
2531:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2532:   while (fifoSize - fifoStart) {
2533:     const PetscInt q   = fifo[fifoStart];
2534:     const PetscInt o   = fifo[fifoStart+1];
2535:     const PetscInt rev = o >= 0 ? 0 : 1;
2536:     const PetscInt off = rev ? -(o+1) : o;

2538:     if (useCone) {
2539:       DMPlexGetConeSize(dm, q, &tmpSize);
2540:       DMPlexGetCone(dm, q, &tmp);
2541:       DMPlexGetConeOrientation(dm, q, &tmpO);
2542:     } else {
2543:       DMPlexGetSupportSize(dm, q, &tmpSize);
2544:       DMPlexGetSupport(dm, q, &tmp);
2545:       tmpO = NULL;
2546:     }
2547:     for (t = 0; t < tmpSize; ++t) {
2548:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2549:       const PetscInt cp = tmp[i];
2550:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2551:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2552:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2553:       PetscInt       co = tmpO ? tmpO[i] : 0;
2554:       PetscInt       c;

2556:       if (rev) {
2557:         PetscInt childSize, coff;
2558:         DMPlexGetConeSize(dm, cp, &childSize);
2559:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2560:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2561:       }
2562:       /* Check for duplicate */
2563:       for (c = 0; c < closureSize; c += 2) {
2564:         if (closure[c] == cp) break;
2565:       }
2566:       if (c == closureSize) {
2567:         closure[closureSize]   = cp;
2568:         closure[closureSize+1] = co;
2569:         fifo[fifoSize]         = cp;
2570:         fifo[fifoSize+1]       = co;
2571:         closureSize           += 2;
2572:         fifoSize              += 2;
2573:       }
2574:     }
2575:     fifoStart += 2;
2576:   }
2577:   if (numPoints) *numPoints = closureSize/2;
2578:   if (points)    *points    = closure;
2579:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2580:   return(0);
2581: }

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

2586:   Not collective

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

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

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

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

2604:   Level: beginner

2606: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2607: @*/
2608: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2609: {

2616:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2617:   if (numPoints) *numPoints = 0;
2618:   return(0);
2619: }

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

2624:   Not collective

2626:   Input Parameter:
2627: . mesh - The DMPlex

2629:   Output Parameters:
2630: + maxConeSize - The maximum number of in-edges
2631: - maxSupportSize - The maximum number of out-edges

2633:   Level: beginner

2635: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2636: @*/
2637: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2638: {
2639:   DM_Plex *mesh = (DM_Plex*) dm->data;

2643:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2644:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2645:   return(0);
2646: }

2648: PetscErrorCode DMSetUp_Plex(DM dm)
2649: {
2650:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2651:   PetscInt       size;

2656:   PetscSectionSetUp(mesh->coneSection);
2657:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2658:   PetscMalloc1(size, &mesh->cones);
2659:   PetscCalloc1(size, &mesh->coneOrientations);
2660:   if (mesh->maxSupportSize) {
2661:     PetscSectionSetUp(mesh->supportSection);
2662:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2663:     PetscMalloc1(size, &mesh->supports);
2664:   }
2665:   return(0);
2666: }

2668: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2669: {

2673:   if (subdm) {DMClone(dm, subdm);}
2674:   DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
2675:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2676:   if (dm->useNatural && dm->sfMigration) {
2677:     PetscSF        sfMigrationInv,sfNatural;
2678:     PetscSection   section, sectionSeq;

2680:     (*subdm)->sfMigration = dm->sfMigration;
2681:     PetscObjectReference((PetscObject) dm->sfMigration);
2682:     DMGetLocalSection((*subdm), &section);
2683:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2684:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
2685:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2687:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2688:     (*subdm)->sfNatural = sfNatural;
2689:     PetscSectionDestroy(&sectionSeq);
2690:     PetscSFDestroy(&sfMigrationInv);
2691:   }
2692:   return(0);
2693: }

2695: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2696: {
2698:   PetscInt       i = 0;

2701:   DMClone(dms[0], superdm);
2702:   DMCreateSectionSuperDM(dms, len, is, superdm);
2703:   (*superdm)->useNatural = PETSC_FALSE;
2704:   for (i = 0; i < len; i++){
2705:     if (dms[i]->useNatural && dms[i]->sfMigration) {
2706:       PetscSF        sfMigrationInv,sfNatural;
2707:       PetscSection   section, sectionSeq;

2709:       (*superdm)->sfMigration = dms[i]->sfMigration;
2710:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
2711:       (*superdm)->useNatural = PETSC_TRUE;
2712:       DMGetLocalSection((*superdm), &section);
2713:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2714:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
2715:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2717:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2718:       (*superdm)->sfNatural = sfNatural;
2719:       PetscSectionDestroy(&sectionSeq);
2720:       PetscSFDestroy(&sfMigrationInv);
2721:       break;
2722:     }
2723:   }
2724:   return(0);
2725: }

2727: /*@
2728:   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information

2730:   Not collective

2732:   Input Parameter:
2733: . mesh - The DMPlex

2735:   Output Parameter:

2737:   Note:
2738:   This should be called after all calls to DMPlexSetCone()

2740:   Level: beginner

2742: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2743: @*/
2744: PetscErrorCode DMPlexSymmetrize(DM dm)
2745: {
2746:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2747:   PetscInt      *offsets;
2748:   PetscInt       supportSize;
2749:   PetscInt       pStart, pEnd, p;

2754:   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2755:   PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);
2756:   /* Calculate support sizes */
2757:   DMPlexGetChart(dm, &pStart, &pEnd);
2758:   for (p = pStart; p < pEnd; ++p) {
2759:     PetscInt dof, off, c;

2761:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2762:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2763:     for (c = off; c < off+dof; ++c) {
2764:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2765:     }
2766:   }
2767:   for (p = pStart; p < pEnd; ++p) {
2768:     PetscInt dof;

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

2772:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2773:   }
2774:   PetscSectionSetUp(mesh->supportSection);
2775:   /* Calculate supports */
2776:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2777:   PetscMalloc1(supportSize, &mesh->supports);
2778:   PetscCalloc1(pEnd - pStart, &offsets);
2779:   for (p = pStart; p < pEnd; ++p) {
2780:     PetscInt dof, off, c;

2782:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2783:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2784:     for (c = off; c < off+dof; ++c) {
2785:       const PetscInt q = mesh->cones[c];
2786:       PetscInt       offS;

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

2790:       mesh->supports[offS+offsets[q]] = p;
2791:       ++offsets[q];
2792:     }
2793:   }
2794:   PetscFree(offsets);
2795:   PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);
2796:   return(0);
2797: }

2799: static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
2800: {
2801:   IS             stratumIS;

2805:   if (pStart >= pEnd) return(0);
2806: #if defined(PETSC_USE_DEBUG)
2807:   {
2808:     PetscInt  qStart, qEnd, numLevels, level;
2809:     PetscBool overlap = PETSC_FALSE;
2810:     DMLabelGetNumValues(label, &numLevels);
2811:     for (level = 0; level < numLevels; level++) {
2812:       DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2813:       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
2814:     }
2815:     if (overlap) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %D range [%D,%D) overlaps with depth %D range [%D,%D)", depth, pStart, pEnd, level, qStart, qEnd);
2816:   }
2817: #endif
2818:   ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);
2819:   DMLabelSetStratumIS(label, depth, stratumIS);
2820:   ISDestroy(&stratumIS);
2821:   return(0);
2822: }

2824: static PetscErrorCode DMPlexCreateDimStratum(DM,DMLabel,DMLabel,PetscInt,PetscInt);

2826: /*@
2827:   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
2828:   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2829:   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2830:   the DAG.

2832:   Collective on dm

2834:   Input Parameter:
2835: . mesh - The DMPlex

2837:   Output Parameter:

2839:   Notes:
2840:   Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
2841:   meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
2842:   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2843:   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
2844:   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.

2846:   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
2847:   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
2848:   we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose
2849:   to interpolate only that one (e0), so that
2850: $  cone(c0) = {e0, v2}
2851: $  cone(e0) = {v0, v1}
2852:   If DMPlexStratify() is run on this mesh, it will give depths
2853: $  depth 0 = {v0, v1, v2}
2854: $  depth 1 = {e0, c0}
2855:   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.

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

2859:   Level: beginner

2861: .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes()
2862: @*/
2863: PetscErrorCode DMPlexStratify(DM dm)
2864: {
2865:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2866:   DMLabel        label;
2867:   PetscInt       pStart, pEnd, p;
2868:   PetscInt       numRoots = 0, numLeaves = 0;
2869:   PetscInt       cMax, fMax, eMax, vMax;

2874:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);

2876:   /* Create depth label */
2877:   DMPlexGetChart(dm, &pStart, &pEnd);
2878:   DMCreateLabel(dm, "depth");
2879:   DMPlexGetDepthLabel(dm, &label);

2881:   {
2882:     /* Initialize roots and count leaves */
2883:     PetscInt sMin = PETSC_MAX_INT;
2884:     PetscInt sMax = PETSC_MIN_INT;
2885:     PetscInt coneSize, supportSize;

2887:     for (p = pStart; p < pEnd; ++p) {
2888:       DMPlexGetConeSize(dm, p, &coneSize);
2889:       DMPlexGetSupportSize(dm, p, &supportSize);
2890:       if (!coneSize && supportSize) {
2891:         sMin = PetscMin(p, sMin);
2892:         sMax = PetscMax(p, sMax);
2893:         ++numRoots;
2894:       } else if (!supportSize && coneSize) {
2895:         ++numLeaves;
2896:       } else if (!supportSize && !coneSize) {
2897:         /* Isolated points */
2898:         sMin = PetscMin(p, sMin);
2899:         sMax = PetscMax(p, sMax);
2900:       }
2901:     }
2902:     DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);
2903:   }

2905:   if (numRoots + numLeaves == (pEnd - pStart)) {
2906:     PetscInt sMin = PETSC_MAX_INT;
2907:     PetscInt sMax = PETSC_MIN_INT;
2908:     PetscInt coneSize, supportSize;

2910:     for (p = pStart; p < pEnd; ++p) {
2911:       DMPlexGetConeSize(dm, p, &coneSize);
2912:       DMPlexGetSupportSize(dm, p, &supportSize);
2913:       if (!supportSize && coneSize) {
2914:         sMin = PetscMin(p, sMin);
2915:         sMax = PetscMax(p, sMax);
2916:       }
2917:     }
2918:     DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);
2919:   } else {
2920:     PetscInt level = 0;
2921:     PetscInt qStart, qEnd, q;

2923:     DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2924:     while (qEnd > qStart) {
2925:       PetscInt sMin = PETSC_MAX_INT;
2926:       PetscInt sMax = PETSC_MIN_INT;

2928:       for (q = qStart; q < qEnd; ++q) {
2929:         const PetscInt *support;
2930:         PetscInt        supportSize, s;

2932:         DMPlexGetSupportSize(dm, q, &supportSize);
2933:         DMPlexGetSupport(dm, q, &support);
2934:         for (s = 0; s < supportSize; ++s) {
2935:           sMin = PetscMin(support[s], sMin);
2936:           sMax = PetscMax(support[s], sMax);
2937:         }
2938:       }
2939:       DMLabelGetNumValues(label, &level);
2940:       DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);
2941:       DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2942:     }
2943:   }
2944:   { /* just in case there is an empty process */
2945:     PetscInt numValues, maxValues = 0, v;

2947:     DMLabelGetNumValues(label, &numValues);
2948:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2949:     for (v = numValues; v < maxValues; v++) {
2950:       DMLabelAddStratum(label, v);
2951:     }
2952:   }
2953:   PetscObjectStateGet((PetscObject) label, &mesh->depthState);

2955:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2956:   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2957:     PetscInt dim;
2958:     DMLabel  dimLabel;

2960:     DMGetDimension(dm, &dim);
2961:     DMCreateLabel(dm, "dim");
2962:     DMGetLabel(dm, "dim", &dimLabel);
2963:     if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2964:     if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2965:     if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2966:     if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2967:   }
2968:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2969:   return(0);
2970: }

2972: /*@
2973:   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.

2975:   Collective on dm

2977:   Input Parameter:
2978: . mesh - The DMPlex

2980:   DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify()

2982:   Level: beginner

2984: .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify()
2985: @*/
2986: PetscErrorCode DMPlexComputeCellTypes(DM dm)
2987: {
2988:   DM_Plex       *mesh;
2989:   DMLabel        label;
2990:   PetscInt       dim, depth, gcStart, gcEnd, pStart, pEnd, p;

2995:   mesh = (DM_Plex *) dm->data;
2996:   DMCreateLabel(dm, "celltype");
2997:   DMPlexGetCellTypeLabel(dm, &label);
2998:   DMGetDimension(dm, &dim);
2999:   DMPlexGetDepth(dm, &depth);
3000:   DMPlexGetChart(dm, &pStart, &pEnd);
3001:   DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);
3002:   for (p = pStart; p < pEnd; ++p) {
3003:     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
3004:     PetscInt       pdepth, pheight, coneSize;

3006:     DMPlexGetPointDepth(dm, p, &pdepth);
3007:     DMPlexGetConeSize(dm, p, &coneSize);
3008:     pheight = depth - pdepth;
3009:     if (depth <= 1) {
3010:       switch (pdepth) {
3011:         case 0: ct = DM_POLYTOPE_POINT;break;
3012:         case 1:
3013:           switch (coneSize) {
3014:             case 2: ct = DM_POLYTOPE_SEGMENT;break;
3015:             case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3016:             case 4:
3017:             switch (dim) {
3018:               case 2: ct = DM_POLYTOPE_QUADRILATERAL;break;
3019:               case 3: ct = DM_POLYTOPE_TETRAHEDRON;break;
3020:               default: break;
3021:             }
3022:             break;
3023:           case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
3024:           case 8: ct = DM_POLYTOPE_HEXAHEDRON;break;
3025:           default: break;
3026:         }
3027:       }
3028:     } else {
3029:       if (pdepth == 0) {
3030:         ct = DM_POLYTOPE_POINT;
3031:       } else if (pheight == 0) {
3032:         if ((p >= gcStart) && (p < gcEnd)) {
3033:           if (coneSize == 1) ct = DM_POLYTOPE_FV_GHOST;
3034:           else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ghost cell %D should have a cone size of 1, not %D", p, coneSize);
3035:         } else {
3036:           switch (dim) {
3037:             case 1:
3038:               switch (coneSize) {
3039:                 case 2: ct = DM_POLYTOPE_SEGMENT;break;
3040:                 default: break;
3041:               }
3042:               break;
3043:             case 2:
3044:               switch (coneSize) {
3045:                 case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3046:                 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
3047:                 default: break;
3048:               }
3049:               break;
3050:             case 3:
3051:               switch (coneSize) {
3052:                 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break;
3053:                 case 5: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
3054:                 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break;
3055:                 default: break;
3056:               }
3057:               break;
3058:             default: break;
3059:           }
3060:         }
3061:       } else if (pheight > 0) {
3062:         switch (coneSize) {
3063:           case 2: ct = DM_POLYTOPE_SEGMENT;break;
3064:           case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3065:           case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
3066:           default: break;
3067:         }
3068:       }
3069:     }
3070:     if (ct == DM_POLYTOPE_UNKNOWN) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %D is screwed up", p);
3071:     DMLabelSetValue(label, p, ct);
3072:   }
3073:   PetscObjectStateGet((PetscObject) label, &mesh->celltypeState);
3074:   PetscObjectViewFromOptions((PetscObject) label, NULL, "-dm_plex_celltypes_view");
3075:   return(0);
3076: }

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

3081:   Not Collective

3083:   Input Parameters:
3084: + dm - The DMPlex object
3085: . numPoints - The number of input points for the join
3086: - points - The input points

3088:   Output Parameters:
3089: + numCoveredPoints - The number of points in the join
3090: - coveredPoints - The points in the join

3092:   Level: intermediate

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

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

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

3102: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
3103: @*/
3104: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3105: {
3106:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3107:   PetscInt      *join[2];
3108:   PetscInt       joinSize, i = 0;
3109:   PetscInt       dof, off, p, c, m;

3117:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
3118:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
3119:   /* Copy in support of first point */
3120:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
3121:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
3122:   for (joinSize = 0; joinSize < dof; ++joinSize) {
3123:     join[i][joinSize] = mesh->supports[off+joinSize];
3124:   }
3125:   /* Check each successive support */
3126:   for (p = 1; p < numPoints; ++p) {
3127:     PetscInt newJoinSize = 0;

3129:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
3130:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
3131:     for (c = 0; c < dof; ++c) {
3132:       const PetscInt point = mesh->supports[off+c];

3134:       for (m = 0; m < joinSize; ++m) {
3135:         if (point == join[i][m]) {
3136:           join[1-i][newJoinSize++] = point;
3137:           break;
3138:         }
3139:       }
3140:     }
3141:     joinSize = newJoinSize;
3142:     i        = 1-i;
3143:   }
3144:   *numCoveredPoints = joinSize;
3145:   *coveredPoints    = join[i];
3146:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3147:   return(0);
3148: }

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

3153:   Not Collective

3155:   Input Parameters:
3156: + dm - The DMPlex object
3157: . numPoints - The number of input points for the join
3158: - points - The input points

3160:   Output Parameters:
3161: + numCoveredPoints - The number of points in the join
3162: - coveredPoints - The points in the join

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

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

3170:   Level: intermediate

3172: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
3173: @*/
3174: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3175: {

3183:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3184:   if (numCoveredPoints) *numCoveredPoints = 0;
3185:   return(0);
3186: }

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

3191:   Not Collective

3193:   Input Parameters:
3194: + dm - The DMPlex object
3195: . numPoints - The number of input points for the join
3196: - points - The input points

3198:   Output Parameters:
3199: + numCoveredPoints - The number of points in the join
3200: - coveredPoints - The points in the join

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

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

3208:   Level: intermediate

3210: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
3211: @*/
3212: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3213: {
3214:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3215:   PetscInt      *offsets, **closures;
3216:   PetscInt      *join[2];
3217:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
3218:   PetscInt       p, d, c, m, ms;


3227:   DMPlexGetDepth(dm, &depth);
3228:   PetscCalloc1(numPoints, &closures);
3229:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3230:   ms      = mesh->maxSupportSize;
3231:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
3232:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
3233:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

3235:   for (p = 0; p < numPoints; ++p) {
3236:     PetscInt closureSize;

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

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

3244:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
3245:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
3246:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3247:           offsets[p*(depth+2)+d+1] = i;
3248:           break;
3249:         }
3250:       }
3251:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
3252:     }
3253:     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);
3254:   }
3255:   for (d = 0; d < depth+1; ++d) {
3256:     PetscInt dof;

3258:     /* Copy in support of first point */
3259:     dof = offsets[d+1] - offsets[d];
3260:     for (joinSize = 0; joinSize < dof; ++joinSize) {
3261:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
3262:     }
3263:     /* Check each successive cone */
3264:     for (p = 1; p < numPoints && joinSize; ++p) {
3265:       PetscInt newJoinSize = 0;

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

3271:         for (m = 0; m < joinSize; ++m) {
3272:           if (point == join[i][m]) {
3273:             join[1-i][newJoinSize++] = point;
3274:             break;
3275:           }
3276:         }
3277:       }
3278:       joinSize = newJoinSize;
3279:       i        = 1-i;
3280:     }
3281:     if (joinSize) break;
3282:   }
3283:   *numCoveredPoints = joinSize;
3284:   *coveredPoints    = join[i];
3285:   for (p = 0; p < numPoints; ++p) {
3286:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
3287:   }
3288:   PetscFree(closures);
3289:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3290:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3291:   return(0);
3292: }

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

3297:   Not Collective

3299:   Input Parameters:
3300: + dm - The DMPlex object
3301: . numPoints - The number of input points for the meet
3302: - points - The input points

3304:   Output Parameters:
3305: + numCoveredPoints - The number of points in the meet
3306: - coveredPoints - The points in the meet

3308:   Level: intermediate

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

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

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

3318: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
3319: @*/
3320: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
3321: {
3322:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3323:   PetscInt      *meet[2];
3324:   PetscInt       meetSize, i = 0;
3325:   PetscInt       dof, off, p, c, m;

3333:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
3334:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
3335:   /* Copy in cone of first point */
3336:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
3337:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
3338:   for (meetSize = 0; meetSize < dof; ++meetSize) {
3339:     meet[i][meetSize] = mesh->cones[off+meetSize];
3340:   }
3341:   /* Check each successive cone */
3342:   for (p = 1; p < numPoints; ++p) {
3343:     PetscInt newMeetSize = 0;

3345:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
3346:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
3347:     for (c = 0; c < dof; ++c) {
3348:       const PetscInt point = mesh->cones[off+c];

3350:       for (m = 0; m < meetSize; ++m) {
3351:         if (point == meet[i][m]) {
3352:           meet[1-i][newMeetSize++] = point;
3353:           break;
3354:         }
3355:       }
3356:     }
3357:     meetSize = newMeetSize;
3358:     i        = 1-i;
3359:   }
3360:   *numCoveringPoints = meetSize;
3361:   *coveringPoints    = meet[i];
3362:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3363:   return(0);
3364: }

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

3369:   Not Collective

3371:   Input Parameters:
3372: + dm - The DMPlex object
3373: . numPoints - The number of input points for the meet
3374: - points - The input points

3376:   Output Parameters:
3377: + numCoveredPoints - The number of points in the meet
3378: - coveredPoints - The points in the meet

3380:   Level: intermediate

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

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

3388: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
3389: @*/
3390: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3391: {

3399:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3400:   if (numCoveredPoints) *numCoveredPoints = 0;
3401:   return(0);
3402: }

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

3407:   Not Collective

3409:   Input Parameters:
3410: + dm - The DMPlex object
3411: . numPoints - The number of input points for the meet
3412: - points - The input points

3414:   Output Parameters:
3415: + numCoveredPoints - The number of points in the meet
3416: - coveredPoints - The points in the meet

3418:   Level: intermediate

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

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

3426: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3427: @*/
3428: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3429: {
3430:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3431:   PetscInt      *offsets, **closures;
3432:   PetscInt      *meet[2];
3433:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
3434:   PetscInt       p, h, c, m, mc;


3443:   DMPlexGetDepth(dm, &height);
3444:   PetscMalloc1(numPoints, &closures);
3445:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3446:   mc      = mesh->maxConeSize;
3447:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3448:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3449:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

3451:   for (p = 0; p < numPoints; ++p) {
3452:     PetscInt closureSize;

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

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

3460:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3461:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3462:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3463:           offsets[p*(height+2)+h+1] = i;
3464:           break;
3465:         }
3466:       }
3467:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3468:     }
3469:     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);
3470:   }
3471:   for (h = 0; h < height+1; ++h) {
3472:     PetscInt dof;

3474:     /* Copy in cone of first point */
3475:     dof = offsets[h+1] - offsets[h];
3476:     for (meetSize = 0; meetSize < dof; ++meetSize) {
3477:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3478:     }
3479:     /* Check each successive cone */
3480:     for (p = 1; p < numPoints && meetSize; ++p) {
3481:       PetscInt newMeetSize = 0;

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

3487:         for (m = 0; m < meetSize; ++m) {
3488:           if (point == meet[i][m]) {
3489:             meet[1-i][newMeetSize++] = point;
3490:             break;
3491:           }
3492:         }
3493:       }
3494:       meetSize = newMeetSize;
3495:       i        = 1-i;
3496:     }
3497:     if (meetSize) break;
3498:   }
3499:   *numCoveredPoints = meetSize;
3500:   *coveredPoints    = meet[i];
3501:   for (p = 0; p < numPoints; ++p) {
3502:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3503:   }
3504:   PetscFree(closures);
3505:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3506:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3507:   return(0);
3508: }

3510: /*@C
3511:   DMPlexEqual - Determine if two DMs have the same topology

3513:   Not Collective

3515:   Input Parameters:
3516: + dmA - A DMPlex object
3517: - dmB - A DMPlex object

3519:   Output Parameters:
3520: . equal - PETSC_TRUE if the topologies are identical

3522:   Level: intermediate

3524:   Notes:
3525:   We are not solving graph isomorphism, so we do not permutation.

3527: .seealso: DMPlexGetCone()
3528: @*/
3529: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3530: {
3531:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


3539:   *equal = PETSC_FALSE;
3540:   DMPlexGetDepth(dmA, &depth);
3541:   DMPlexGetDepth(dmB, &depthB);
3542:   if (depth != depthB) return(0);
3543:   DMPlexGetChart(dmA, &pStart,  &pEnd);
3544:   DMPlexGetChart(dmB, &pStartB, &pEndB);
3545:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3546:   for (p = pStart; p < pEnd; ++p) {
3547:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3548:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

3550:     DMPlexGetConeSize(dmA, p, &coneSize);
3551:     DMPlexGetCone(dmA, p, &cone);
3552:     DMPlexGetConeOrientation(dmA, p, &ornt);
3553:     DMPlexGetConeSize(dmB, p, &coneSizeB);
3554:     DMPlexGetCone(dmB, p, &coneB);
3555:     DMPlexGetConeOrientation(dmB, p, &orntB);
3556:     if (coneSize != coneSizeB) return(0);
3557:     for (c = 0; c < coneSize; ++c) {
3558:       if (cone[c] != coneB[c]) return(0);
3559:       if (ornt[c] != orntB[c]) return(0);
3560:     }
3561:     DMPlexGetSupportSize(dmA, p, &supportSize);
3562:     DMPlexGetSupport(dmA, p, &support);
3563:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
3564:     DMPlexGetSupport(dmB, p, &supportB);
3565:     if (supportSize != supportSizeB) return(0);
3566:     for (s = 0; s < supportSize; ++s) {
3567:       if (support[s] != supportB[s]) return(0);
3568:     }
3569:   }
3570:   *equal = PETSC_TRUE;
3571:   return(0);
3572: }

3574: /*@C
3575:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

3577:   Not Collective

3579:   Input Parameters:
3580: + dm         - The DMPlex
3581: . cellDim    - The cell dimension
3582: - numCorners - The number of vertices on a cell

3584:   Output Parameters:
3585: . numFaceVertices - The number of vertices on a face

3587:   Level: developer

3589:   Notes:
3590:   Of course this can only work for a restricted set of symmetric shapes

3592: .seealso: DMPlexGetCone()
3593: @*/
3594: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3595: {
3596:   MPI_Comm       comm;

3600:   PetscObjectGetComm((PetscObject)dm,&comm);
3602:   switch (cellDim) {
3603:   case 0:
3604:     *numFaceVertices = 0;
3605:     break;
3606:   case 1:
3607:     *numFaceVertices = 1;
3608:     break;
3609:   case 2:
3610:     switch (numCorners) {
3611:     case 3: /* triangle */
3612:       *numFaceVertices = 2; /* Edge has 2 vertices */
3613:       break;
3614:     case 4: /* quadrilateral */
3615:       *numFaceVertices = 2; /* Edge has 2 vertices */
3616:       break;
3617:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3618:       *numFaceVertices = 3; /* Edge has 3 vertices */
3619:       break;
3620:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3621:       *numFaceVertices = 3; /* Edge has 3 vertices */
3622:       break;
3623:     default:
3624:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3625:     }
3626:     break;
3627:   case 3:
3628:     switch (numCorners) {
3629:     case 4: /* tetradehdron */
3630:       *numFaceVertices = 3; /* Face has 3 vertices */
3631:       break;
3632:     case 6: /* tet cohesive cells */
3633:       *numFaceVertices = 4; /* Face has 4 vertices */
3634:       break;
3635:     case 8: /* hexahedron */
3636:       *numFaceVertices = 4; /* Face has 4 vertices */
3637:       break;
3638:     case 9: /* tet cohesive Lagrange cells */
3639:       *numFaceVertices = 6; /* Face has 6 vertices */
3640:       break;
3641:     case 10: /* quadratic tetrahedron */
3642:       *numFaceVertices = 6; /* Face has 6 vertices */
3643:       break;
3644:     case 12: /* hex cohesive Lagrange cells */
3645:       *numFaceVertices = 6; /* Face has 6 vertices */
3646:       break;
3647:     case 18: /* quadratic tet cohesive Lagrange cells */
3648:       *numFaceVertices = 6; /* Face has 6 vertices */
3649:       break;
3650:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3651:       *numFaceVertices = 9; /* Face has 9 vertices */
3652:       break;
3653:     default:
3654:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3655:     }
3656:     break;
3657:   default:
3658:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3659:   }
3660:   return(0);
3661: }

3663: /*@
3664:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

3666:   Not Collective

3668:   Input Parameter:
3669: . dm    - The DMPlex object

3671:   Output Parameter:
3672: . depthLabel - The DMLabel recording point depth

3674:   Level: developer

3676: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3677: @*/
3678: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3679: {
3683:   *depthLabel = dm->depthLabel;
3684:   return(0);
3685: }

3687: /*@
3688:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

3690:   Not Collective

3692:   Input Parameter:
3693: . dm    - The DMPlex object

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

3698:   Level: developer

3700:   Notes:
3701:   This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
3702:   The point depth is described more in detail in DMPlexSymmetrize().

3704: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexSymmetrize()
3705: @*/
3706: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3707: {
3708:   DMLabel        label;
3709:   PetscInt       d = 0;

3715:   DMPlexGetDepthLabel(dm, &label);
3716:   if (label) {DMLabelGetNumValues(label, &d);}
3717:   *depth = d-1;
3718:   return(0);
3719: }

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

3724:   Not Collective

3726:   Input Parameters:
3727: + dm           - The DMPlex object
3728: - stratumValue - The requested depth

3730:   Output Parameters:
3731: + start - The first point at this depth
3732: - end   - One beyond the last point at this depth

3734:   Notes:
3735:   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
3736:   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
3737:   higher dimension, e.g., "edges".

3739:   Level: developer

3741: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3742: @*/
3743: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3744: {
3745:   DMLabel        label;
3746:   PetscInt       pStart, pEnd;

3753:   DMPlexGetChart(dm, &pStart, &pEnd);
3754:   if (pStart == pEnd) return(0);
3755:   if (stratumValue < 0) {
3756:     if (start) *start = pStart;
3757:     if (end)   *end   = pEnd;
3758:     return(0);
3759:   }
3760:   DMPlexGetDepthLabel(dm, &label);
3761:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3762:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3763:   return(0);
3764: }

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

3769:   Not Collective

3771:   Input Parameters:
3772: + dm           - The DMPlex object
3773: - stratumValue - The requested height

3775:   Output Parameters:
3776: + start - The first point at this height
3777: - end   - One beyond the last point at this height

3779:   Notes:
3780:   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
3781:   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
3782:   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".

3784:   Level: developer

3786: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3787: @*/
3788: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3789: {
3790:   DMLabel        label;
3791:   PetscInt       depth, pStart, pEnd;

3798:   DMPlexGetChart(dm, &pStart, &pEnd);
3799:   if (pStart == pEnd) return(0);
3800:   if (stratumValue < 0) {
3801:     if (start) *start = pStart;
3802:     if (end)   *end   = pEnd;
3803:     return(0);
3804:   }
3805:   DMPlexGetDepthLabel(dm, &label);
3806:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3807:   DMLabelGetNumValues(label, &depth);
3808:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3809:   return(0);
3810: }

3812: /*@
3813:   DMPlexGetPointDepth - Get the depth of a given point

3815:   Not Collective

3817:   Input Parameter:
3818: + dm    - The DMPlex object
3819: - point - The point

3821:   Output Parameter:
3822: . depth - The depth of the point

3824:   Level: intermediate

3826: .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth()
3827: @*/
3828: PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
3829: {

3835:   DMLabelGetValue(dm->depthLabel, point, depth);
3836:   return(0);
3837: }

3839: /*@
3840:   DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell

3842:   Not Collective

3844:   Input Parameter:
3845: . dm - The DMPlex object

3847:   Output Parameter:
3848: . celltypeLabel - The DMLabel recording cell polytope type

3850:   Level: developer

3852: .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth()
3853: @*/
3854: PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
3855: {

3861:   if (!dm->celltypeLabel) {DMPlexComputeCellTypes(dm);}
3862:   *celltypeLabel = dm->celltypeLabel;
3863:   return(0);
3864: }

3866: /*@
3867:   DMPlexGetCellType - Get the polytope type of a given cell

3869:   Not Collective

3871:   Input Parameter:
3872: + dm   - The DMPlex object
3873: - cell - The cell

3875:   Output Parameter:
3876: . celltype - The polytope type of the cell

3878:   Level: intermediate

3880: .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth()
3881: @*/
3882: PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
3883: {
3884:   DMLabel        label;
3885:   PetscInt       ct;

3891:   DMPlexGetCellTypeLabel(dm, &label);
3892:   DMLabelGetValue(label, cell, &ct);
3893:   *celltype = (DMPolytopeType) ct;
3894:   return(0);
3895: }

3897: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3898: {
3899:   PetscSection   section, s;
3900:   Mat            m;
3901:   PetscInt       maxHeight;

3905:   DMClone(dm, cdm);
3906:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3907:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3908:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3909:   DMSetLocalSection(*cdm, section);
3910:   PetscSectionDestroy(&section);
3911:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3912:   MatCreate(PETSC_COMM_SELF, &m);
3913:   DMSetDefaultConstraints(*cdm, s, m);
3914:   PetscSectionDestroy(&s);
3915:   MatDestroy(&m);

3917:   DMSetNumFields(*cdm, 1);
3918:   DMCreateDS(*cdm);
3919:   return(0);
3920: }

3922: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3923: {
3924:   Vec            coordsLocal;
3925:   DM             coordsDM;

3929:   *field = NULL;
3930:   DMGetCoordinatesLocal(dm,&coordsLocal);
3931:   DMGetCoordinateDM(dm,&coordsDM);
3932:   if (coordsLocal && coordsDM) {
3933:     DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3934:   }
3935:   return(0);
3936: }

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

3941:   Not Collective

3943:   Input Parameters:
3944: . dm        - The DMPlex object

3946:   Output Parameter:
3947: . section - The PetscSection object

3949:   Level: developer

3951: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3952: @*/
3953: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3954: {
3955:   DM_Plex *mesh = (DM_Plex*) dm->data;

3959:   if (section) *section = mesh->coneSection;
3960:   return(0);
3961: }

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

3966:   Not Collective

3968:   Input Parameters:
3969: . dm        - The DMPlex object

3971:   Output Parameter:
3972: . section - The PetscSection object

3974:   Level: developer

3976: .seealso: DMPlexGetConeSection()
3977: @*/
3978: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3979: {
3980:   DM_Plex *mesh = (DM_Plex*) dm->data;

3984:   if (section) *section = mesh->supportSection;
3985:   return(0);
3986: }

3988: /*@C
3989:   DMPlexGetCones - Return cone data

3991:   Not Collective

3993:   Input Parameters:
3994: . dm        - The DMPlex object

3996:   Output Parameter:
3997: . cones - The cone for each point

3999:   Level: developer

4001: .seealso: DMPlexGetConeSection()
4002: @*/
4003: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
4004: {
4005:   DM_Plex *mesh = (DM_Plex*) dm->data;

4009:   if (cones) *cones = mesh->cones;
4010:   return(0);
4011: }

4013: /*@C
4014:   DMPlexGetConeOrientations - Return cone orientation data

4016:   Not Collective

4018:   Input Parameters:
4019: . dm        - The DMPlex object

4021:   Output Parameter:
4022: . coneOrientations - The cone orientation for each point

4024:   Level: developer

4026: .seealso: DMPlexGetConeSection()
4027: @*/
4028: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
4029: {
4030:   DM_Plex *mesh = (DM_Plex*) dm->data;

4034:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
4035:   return(0);
4036: }

4038: /******************************** FEM Support **********************************/

4040: /*
4041:  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
4042:  representing a line in the section.
4043: */
4044: static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
4045: {

4049:   PetscSectionGetFieldComponents(section, field, Nc);
4050:   if (line < 0) {
4051:     *k = 0;
4052:     *Nc = 0;
4053:   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
4054:     *k = 1;
4055:   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
4056:     /* An order k SEM disc has k-1 dofs on an edge */
4057:     PetscSectionGetFieldDof(section, line, field, k);
4058:     *k = *k / *Nc + 1;
4059:   }
4060:   return(0);
4061: }

4063: /*@

4065:   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
4066:   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
4067:   section provided (or the section of the DM).

4069:   Input Parameters:
4070: + dm      - The DM
4071: . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
4072: - section - The PetscSection to reorder, or NULL for the default section

4074:   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
4075:   degree of the basis.

4077:   Example:
4078:   A typical interpolated single-quad mesh might order points as
4079: .vb
4080:   [c0, v1, v2, v3, v4, e5, e6, e7, e8]

4082:   v4 -- e6 -- v3
4083:   |           |
4084:   e7    c0    e8
4085:   |           |
4086:   v1 -- e5 -- v2
4087: .ve

4089:   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
4090:   dofs in the order of points, e.g.,
4091: .vb
4092:     c0 -> [0,1,2,3]
4093:     v1 -> [4]
4094:     ...
4095:     e5 -> [8, 9]
4096: .ve

4098:   which corresponds to the dofs
4099: .vb
4100:     6   10  11  7
4101:     13  2   3   15
4102:     12  0   1   14
4103:     4   8   9   5
4104: .ve

4106:   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
4107: .vb
4108:   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
4109: .ve

4111:   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
4112: .vb
4113:    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
4114: .ve

4116:   Level: developer

4118: .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection()
4119: @*/
4120: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
4121: {
4122:   DMLabel        label;
4123:   PetscInt      *perm;
4124:   PetscInt       dim, depth = -1, eStart = -1, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
4125:   PetscBool      vertexchart;

4129:   DMGetDimension(dm, &dim);
4130:   if (dim < 1) return(0);
4131:   if (point < 0) {
4132:     PetscInt sStart,sEnd;

4134:     DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);
4135:     point = sEnd-sStart ? sStart : point;
4136:   }
4137:   DMPlexGetDepthLabel(dm, &label);
4138:   if (point >= 0) { DMLabelGetValue(label, point, &depth); }
4139:   if (!section) {DMGetLocalSection(dm, &section);}
4140:   if (depth == 1) {eStart = point;}
4141:   else if  (depth == dim) {
4142:     const PetscInt *cone;

4144:     DMPlexGetCone(dm, point, &cone);
4145:     if (dim == 2) eStart = cone[0];
4146:     else if (dim == 3) {
4147:       const PetscInt *cone2;
4148:       DMPlexGetCone(dm, cone[0], &cone2);
4149:       eStart = cone2[0];
4150:     } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim);
4151:   } else if (depth >= 0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim);
4152:   {                             /* Determine whether the chart covers all points or just vertices. */
4153:     PetscInt pStart,pEnd,cStart,cEnd;
4154:     DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);
4155:     PetscSectionGetChart(section,&cStart,&cEnd);
4156:     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */
4157:     else vertexchart = PETSC_FALSE;                                 /* Assume all interpolated points are in chart */
4158:   }
4159:   PetscSectionGetNumFields(section, &Nf);
4160:   for (f = 0; f < Nf; ++f) {
4161:     PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
4162:     size += PetscPowInt(k+1, dim)*Nc;
4163:   }
4164:   PetscMalloc1(size, &perm);
4165:   for (f = 0; f < Nf; ++f) {
4166:     switch (dim) {
4167:     case 1:
4168:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
4169:       /*
4170:         Original ordering is [ edge of length k-1; vtx0; vtx1 ]
4171:         We want              [ vtx0; edge of length k-1; vtx1 ]
4172:       */
4173:       for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
4174:       for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
4175:       for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
4176:       foffset = offset;
4177:       break;
4178:     case 2:
4179:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
4180:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
4181:       /* The SEM order is

4183:          v_lb, {e_b}, v_rb,
4184:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
4185:          v_lt, reverse {e_t}, v_rt
4186:       */
4187:       {
4188:         const PetscInt of   = 0;
4189:         const PetscInt oeb  = of   + PetscSqr(k-1);
4190:         const PetscInt oer  = oeb  + (k-1);
4191:         const PetscInt oet  = oer  + (k-1);
4192:         const PetscInt oel  = oet  + (k-1);
4193:         const PetscInt ovlb = oel  + (k-1);
4194:         const PetscInt ovrb = ovlb + 1;
4195:         const PetscInt ovrt = ovrb + 1;
4196:         const PetscInt ovlt = ovrt + 1;
4197:         PetscInt       o;

4199:         /* bottom */
4200:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
4201:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4202:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
4203:         /* middle */
4204:         for (i = 0; i < k-1; ++i) {
4205:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
4206:           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;
4207:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
4208:         }
4209:         /* top */
4210:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
4211:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4212:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
4213:         foffset = offset;
4214:       }
4215:       break;
4216:     case 3:
4217:       /* The original hex closure is

4219:          {c,
4220:           f_b, f_t, f_f, f_b, f_r, f_l,
4221:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
4222:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
4223:       */
4224:       PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);
4225:       /* The SEM order is
4226:          Bottom Slice
4227:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
4228:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
4229:          v_blb, {e_bb}, v_brb,

4231:          Middle Slice (j)
4232:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
4233:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
4234:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

4236:          Top Slice
4237:          v_tlf, {e_tf}, v_trf,
4238:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
4239:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
4240:       */
4241:       {
4242:         const PetscInt oc    = 0;
4243:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
4244:         const PetscInt oft   = ofb   + PetscSqr(k-1);
4245:         const PetscInt off   = oft   + PetscSqr(k-1);
4246:         const PetscInt ofk   = off   + PetscSqr(k-1);
4247:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
4248:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
4249:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
4250:         const PetscInt oebb  = oebl  + (k-1);
4251:         const PetscInt oebr  = oebb  + (k-1);
4252:         const PetscInt oebf  = oebr  + (k-1);
4253:         const PetscInt oetf  = oebf  + (k-1);
4254:         const PetscInt oetr  = oetf  + (k-1);
4255:         const PetscInt oetb  = oetr  + (k-1);
4256:         const PetscInt oetl  = oetb  + (k-1);
4257:         const PetscInt oerf  = oetl  + (k-1);
4258:         const PetscInt oelf  = oerf  + (k-1);
4259:         const PetscInt oelb  = oelf  + (k-1);
4260:         const PetscInt oerb  = oelb  + (k-1);
4261:         const PetscInt ovblf = oerb  + (k-1);
4262:         const PetscInt ovblb = ovblf + 1;
4263:         const PetscInt ovbrb = ovblb + 1;
4264:         const PetscInt ovbrf = ovbrb + 1;
4265:         const PetscInt ovtlf = ovbrf + 1;
4266:         const PetscInt ovtrf = ovtlf + 1;
4267:         const PetscInt ovtrb = ovtrf + 1;
4268:         const PetscInt ovtlb = ovtrb + 1;
4269:         PetscInt       o, n;

4271:         /* Bottom Slice */
4272:         /*   bottom */
4273:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
4274:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4275:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
4276:         /*   middle */
4277:         for (i = 0; i < k-1; ++i) {
4278:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
4279:           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;}
4280:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
4281:         }
4282:         /*   top */
4283:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
4284:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4285:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

4287:         /* Middle Slice */
4288:         for (j = 0; j < k-1; ++j) {
4289:           /*   bottom */
4290:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
4291:           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;
4292:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
4293:           /*   middle */
4294:           for (i = 0; i < k-1; ++i) {
4295:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
4296:             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;
4297:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
4298:           }
4299:           /*   top */
4300:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
4301:           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;
4302:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
4303:         }

4305:         /* Top Slice */
4306:         /*   bottom */
4307:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
4308:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4309:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
4310:         /*   middle */
4311:         for (i = 0; i < k-1; ++i) {
4312:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
4313:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
4314:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
4315:         }
4316:         /*   top */
4317:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
4318:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4319:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

4321:         foffset = offset;
4322:       }
4323:       break;
4324:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
4325:     }
4326:   }
4327:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
4328:   /* Check permutation */
4329:   {
4330:     PetscInt *check;

4332:     PetscMalloc1(size, &check);
4333:     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]);}
4334:     for (i = 0; i < size; ++i) check[perm[i]] = i;
4335:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
4336:     PetscFree(check);
4337:   }
4338:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
4339:   return(0);
4340: }

4342: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
4343: {
4344:   PetscDS        prob;
4345:   PetscInt       depth, Nf, h;
4346:   DMLabel        label;

4350:   DMGetDS(dm, &prob);
4351:   Nf      = prob->Nf;
4352:   label   = dm->depthLabel;
4353:   *dspace = NULL;
4354:   if (field < Nf) {
4355:     PetscObject disc = prob->disc[field];

4357:     if (disc->classid == PETSCFE_CLASSID) {
4358:       PetscDualSpace dsp;

4360:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
4361:       DMLabelGetNumValues(label,&depth);
4362:       DMLabelGetValue(label,point,&h);
4363:       h    = depth - 1 - h;
4364:       if (h) {
4365:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
4366:       } else {
4367:         *dspace = dsp;
4368:       }
4369:     }
4370:   }
4371:   return(0);
4372: }


4375: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4376: {
4377:   PetscScalar    *array, *vArray;
4378:   const PetscInt *cone, *coneO;
4379:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
4380:   PetscErrorCode  ierr;

4383:   PetscSectionGetChart(section, &pStart, &pEnd);
4384:   DMPlexGetConeSize(dm, point, &numPoints);
4385:   DMPlexGetCone(dm, point, &cone);
4386:   DMPlexGetConeOrientation(dm, point, &coneO);
4387:   if (!values || !*values) {
4388:     if ((point >= pStart) && (point < pEnd)) {
4389:       PetscInt dof;

4391:       PetscSectionGetDof(section, point, &dof);
4392:       size += dof;
4393:     }
4394:     for (p = 0; p < numPoints; ++p) {
4395:       const PetscInt cp = cone[p];
4396:       PetscInt       dof;

4398:       if ((cp < pStart) || (cp >= pEnd)) continue;
4399:       PetscSectionGetDof(section, cp, &dof);
4400:       size += dof;
4401:     }
4402:     if (!values) {
4403:       if (csize) *csize = size;
4404:       return(0);
4405:     }
4406:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
4407:   } else {
4408:     array = *values;
4409:   }
4410:   size = 0;
4411:   VecGetArray(v, &vArray);
4412:   if ((point >= pStart) && (point < pEnd)) {
4413:     PetscInt     dof, off, d;
4414:     PetscScalar *varr;

4416:     PetscSectionGetDof(section, point, &dof);
4417:     PetscSectionGetOffset(section, point, &off);
4418:     varr = &vArray[off];
4419:     for (d = 0; d < dof; ++d, ++offset) {
4420:       array[offset] = varr[d];
4421:     }
4422:     size += dof;
4423:   }
4424:   for (p = 0; p < numPoints; ++p) {
4425:     const PetscInt cp = cone[p];
4426:     PetscInt       o  = coneO[p];
4427:     PetscInt       dof, off, d;
4428:     PetscScalar   *varr;

4430:     if ((cp < pStart) || (cp >= pEnd)) continue;
4431:     PetscSectionGetDof(section, cp, &dof);
4432:     PetscSectionGetOffset(section, cp, &off);
4433:     varr = &vArray[off];
4434:     if (o >= 0) {
4435:       for (d = 0; d < dof; ++d, ++offset) {
4436:         array[offset] = varr[d];
4437:       }
4438:     } else {
4439:       for (d = dof-1; d >= 0; --d, ++offset) {
4440:         array[offset] = varr[d];
4441:       }
4442:     }
4443:     size += dof;
4444:   }
4445:   VecRestoreArray(v, &vArray);
4446:   if (!*values) {
4447:     if (csize) *csize = size;
4448:     *values = array;
4449:   } else {
4450:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4451:     *csize = size;
4452:   }
4453:   return(0);
4454: }

4456: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4457: {
4458:   const PetscInt *cla;
4459:   PetscInt       np, *pts = NULL;

4463:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
4464:   if (!*clPoints) {
4465:     PetscInt pStart, pEnd, p, q;

4467:     PetscSectionGetChart(section, &pStart, &pEnd);
4468:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
4469:     /* Compress out points not in the section */
4470:     for (p = 0, q = 0; p < np; p++) {
4471:       PetscInt r = pts[2*p];
4472:       if ((r >= pStart) && (r < pEnd)) {
4473:         pts[q*2]   = r;
4474:         pts[q*2+1] = pts[2*p+1];
4475:         ++q;
4476:       }
4477:     }
4478:     np = q;
4479:     cla = NULL;
4480:   } else {
4481:     PetscInt dof, off;

4483:     PetscSectionGetDof(*clSec, point, &dof);
4484:     PetscSectionGetOffset(*clSec, point, &off);
4485:     ISGetIndices(*clPoints, &cla);
4486:     np   = dof/2;
4487:     pts  = (PetscInt *) &cla[off];
4488:   }
4489:   *numPoints = np;
4490:   *points    = pts;
4491:   *clp       = cla;

4493:   return(0);
4494: }

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

4501:   if (!*clPoints) {
4502:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
4503:   } else {
4504:     ISRestoreIndices(*clPoints, clp);
4505:   }
4506:   *numPoints = 0;
4507:   *points    = NULL;
4508:   *clSec     = NULL;
4509:   *clPoints  = NULL;
4510:   *clp       = NULL;
4511:   return(0);
4512: }

4514: 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[])
4515: {
4516:   PetscInt          offset = 0, p;
4517:   const PetscInt    **perms = NULL;
4518:   const PetscScalar **flips = NULL;
4519:   PetscErrorCode    ierr;

4522:   *size = 0;
4523:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4524:   for (p = 0; p < numPoints; p++) {
4525:     const PetscInt    point = points[2*p];
4526:     const PetscInt    *perm = perms ? perms[p] : NULL;
4527:     const PetscScalar *flip = flips ? flips[p] : NULL;
4528:     PetscInt          dof, off, d;
4529:     const PetscScalar *varr;

4531:     PetscSectionGetDof(section, point, &dof);
4532:     PetscSectionGetOffset(section, point, &off);
4533:     varr = &vArray[off];
4534:     if (clperm) {
4535:       if (perm) {
4536:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4537:       } else {
4538:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4539:       }
4540:       if (flip) {
4541:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4542:       }
4543:     } else {
4544:       if (perm) {
4545:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4546:       } else {
4547:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4548:       }
4549:       if (flip) {
4550:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4551:       }
4552:     }
4553:     offset += dof;
4554:   }
4555:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4556:   *size = offset;
4557:   return(0);
4558: }

4560: 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[])
4561: {
4562:   PetscInt          offset = 0, f;
4563:   PetscErrorCode    ierr;

4566:   *size = 0;
4567:   for (f = 0; f < numFields; ++f) {
4568:     PetscInt          p;
4569:     const PetscInt    **perms = NULL;
4570:     const PetscScalar **flips = NULL;

4572:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4573:     for (p = 0; p < numPoints; p++) {
4574:       const PetscInt    point = points[2*p];
4575:       PetscInt          fdof, foff, b;
4576:       const PetscScalar *varr;
4577:       const PetscInt    *perm = perms ? perms[p] : NULL;
4578:       const PetscScalar *flip = flips ? flips[p] : NULL;

4580:       PetscSectionGetFieldDof(section, point, f, &fdof);
4581:       PetscSectionGetFieldOffset(section, point, f, &foff);
4582:       varr = &vArray[foff];
4583:       if (clperm) {
4584:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4585:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4586:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4587:       } else {
4588:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4589:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4590:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4591:       }
4592:       offset += fdof;
4593:     }
4594:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4595:   }
4596:   *size = offset;
4597:   return(0);
4598: }

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

4603:   Not collective

4605:   Input Parameters:
4606: + dm - The DM
4607: . section - The section describing the layout in v, or NULL to use the default section
4608: . v - The local vector
4609: . point - The point in the DM
4610: . csize - The size of the input values array, or NULL
4611: - values - An array to use for the values, or NULL to have it allocated automatically

4613:   Output Parameters:
4614: + csize - The number of values in the closure
4615: - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed

4617: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4618: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4619: $ assembly function, and a user may already have allocated storage for this operation.
4620: $
4621: $ A typical use could be
4622: $
4623: $  values = NULL;
4624: $  DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4625: $  for (cl = 0; cl < clSize; ++cl) {
4626: $    <Compute on closure>
4627: $  }
4628: $  DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4629: $
4630: $ or
4631: $
4632: $  PetscMalloc1(clMaxSize, &values);
4633: $  for (p = pStart; p < pEnd; ++p) {
4634: $    clSize = clMaxSize;
4635: $    DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4636: $    for (cl = 0; cl < clSize; ++cl) {
4637: $      <Compute on closure>
4638: $    }
4639: $  }
4640: $  PetscFree(values);

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

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

4648:   Level: intermediate

4650: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4651: @*/
4652: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4653: {
4654:   PetscSection       clSection;
4655:   IS                 clPoints;
4656:   PetscScalar       *array;
4657:   const PetscScalar *vArray;
4658:   PetscInt          *points = NULL;
4659:   const PetscInt    *clp, *perm;
4660:   PetscInt           depth, numFields, numPoints, size;
4661:   PetscErrorCode     ierr;

4665:   if (!section) {DMGetLocalSection(dm, &section);}
4668:   DMPlexGetDepth(dm, &depth);
4669:   PetscSectionGetNumFields(section, &numFields);
4670:   if (depth == 1 && numFields < 2) {
4671:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4672:     return(0);
4673:   }
4674:   /* Get points */
4675:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4676:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4677:   /* Get array */
4678:   if (!values || !*values) {
4679:     PetscInt asize = 0, dof, p;

4681:     for (p = 0; p < numPoints*2; p += 2) {
4682:       PetscSectionGetDof(section, points[p], &dof);
4683:       asize += dof;
4684:     }
4685:     if (!values) {
4686:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4687:       if (csize) *csize = asize;
4688:       return(0);
4689:     }
4690:     DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4691:   } else {
4692:     array = *values;
4693:   }
4694:   VecGetArrayRead(v, &vArray);
4695:   /* Get values */
4696:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4697:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4698:   /* Cleanup points */
4699:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4700:   /* Cleanup array */
4701:   VecRestoreArrayRead(v, &vArray);
4702:   if (!*values) {
4703:     if (csize) *csize = size;
4704:     *values = array;
4705:   } else {
4706:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4707:     *csize = size;
4708:   }
4709:   return(0);
4710: }

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

4715:   Not collective

4717:   Input Parameters:
4718: + dm - The DM
4719: . section - The section describing the layout in v, or NULL to use the default section
4720: . v - The local vector
4721: . point - The point in the DM
4722: . csize - The number of values in the closure, or NULL
4723: - values - The array of values, which is a borrowed array and should not be freed

4725:   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()

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

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

4733:   Level: intermediate

4735: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4736: @*/
4737: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4738: {
4739:   PetscInt       size = 0;

4743:   /* Should work without recalculating size */
4744:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4745:   *values = NULL;
4746:   return(0);
4747: }

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

4752: 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[])
4753: {
4754:   PetscInt        cdof;   /* The number of constraints on this point */
4755:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4756:   PetscScalar    *a;
4757:   PetscInt        off, cind = 0, k;
4758:   PetscErrorCode  ierr;

4761:   PetscSectionGetConstraintDof(section, point, &cdof);
4762:   PetscSectionGetOffset(section, point, &off);
4763:   a    = &array[off];
4764:   if (!cdof || setBC) {
4765:     if (clperm) {
4766:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4767:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4768:     } else {
4769:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4770:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4771:     }
4772:   } else {
4773:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4774:     if (clperm) {
4775:       if (perm) {for (k = 0; k < dof; ++k) {
4776:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4777:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4778:         }
4779:       } else {
4780:         for (k = 0; k < dof; ++k) {
4781:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4782:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4783:         }
4784:       }
4785:     } else {
4786:       if (perm) {
4787:         for (k = 0; k < dof; ++k) {
4788:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4789:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4790:         }
4791:       } else {
4792:         for (k = 0; k < dof; ++k) {
4793:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4794:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4795:         }
4796:       }
4797:     }
4798:   }
4799:   return(0);
4800: }

4802: 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[])
4803: {
4804:   PetscInt        cdof;   /* The number of constraints on this point */
4805:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4806:   PetscScalar    *a;
4807:   PetscInt        off, cind = 0, k;
4808:   PetscErrorCode  ierr;

4811:   PetscSectionGetConstraintDof(section, point, &cdof);
4812:   PetscSectionGetOffset(section, point, &off);
4813:   a    = &array[off];
4814:   if (cdof) {
4815:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4816:     if (clperm) {
4817:       if (perm) {
4818:         for (k = 0; k < dof; ++k) {
4819:           if ((cind < cdof) && (k == cdofs[cind])) {
4820:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4821:             cind++;
4822:           }
4823:         }
4824:       } else {
4825:         for (k = 0; k < dof; ++k) {
4826:           if ((cind < cdof) && (k == cdofs[cind])) {
4827:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4828:             cind++;
4829:           }
4830:         }
4831:       }
4832:     } else {
4833:       if (perm) {
4834:         for (k = 0; k < dof; ++k) {
4835:           if ((cind < cdof) && (k == cdofs[cind])) {
4836:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4837:             cind++;
4838:           }
4839:         }
4840:       } else {
4841:         for (k = 0; k < dof; ++k) {
4842:           if ((cind < cdof) && (k == cdofs[cind])) {
4843:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4844:             cind++;
4845:           }
4846:         }
4847:       }
4848:     }
4849:   }
4850:   return(0);
4851: }

4853: 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[])
4854: {
4855:   PetscScalar    *a;
4856:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4857:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4858:   PetscInt        cind = 0, b;
4859:   PetscErrorCode  ierr;

4862:   PetscSectionGetFieldDof(section, point, f, &fdof);
4863:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4864:   PetscSectionGetFieldOffset(section, point, f, &foff);
4865:   a    = &array[foff];
4866:   if (!fcdof || setBC) {
4867:     if (clperm) {
4868:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4869:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4870:     } else {
4871:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4872:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4873:     }
4874:   } else {
4875:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4876:     if (clperm) {
4877:       if (perm) {
4878:         for (b = 0; b < fdof; b++) {
4879:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4880:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4881:         }
4882:       } else {
4883:         for (b = 0; b < fdof; b++) {
4884:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4885:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4886:         }
4887:       }
4888:     } else {
4889:       if (perm) {
4890:         for (b = 0; b < fdof; b++) {
4891:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4892:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4893:         }
4894:       } else {
4895:         for (b = 0; b < fdof; b++) {
4896:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4897:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4898:         }
4899:       }
4900:     }
4901:   }
4902:   *offset += fdof;
4903:   return(0);
4904: }

4906: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4907: {
4908:   PetscScalar    *a;
4909:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4910:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4911:   PetscInt        cind = 0, ncind = 0, b;
4912:   PetscBool       ncSet, fcSet;
4913:   PetscErrorCode  ierr;

4916:   PetscSectionGetFieldDof(section, point, f, &fdof);
4917:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4918:   PetscSectionGetFieldOffset(section, point, f, &foff);
4919:   a    = &array[foff];
4920:   if (fcdof) {
4921:     /* We just override fcdof and fcdofs with Ncc and comps */
4922:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4923:     if (clperm) {
4924:       if (perm) {
4925:         if (comps) {
4926:           for (b = 0; b < fdof; b++) {
4927:             ncSet = fcSet = PETSC_FALSE;
4928:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4929:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4930:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4931:           }
4932:         } else {
4933:           for (b = 0; b < fdof; b++) {
4934:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4935:               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4936:               ++cind;
4937:             }
4938:           }
4939:         }
4940:       } else {
4941:         if (comps) {
4942:           for (b = 0; b < fdof; b++) {
4943:             ncSet = fcSet = PETSC_FALSE;
4944:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4945:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4946:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4947:           }
4948:         } else {
4949:           for (b = 0; b < fdof; b++) {
4950:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4951:               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4952:               ++cind;
4953:             }
4954:           }
4955:         }
4956:       }
4957:     } else {
4958:       if (perm) {
4959:         if (comps) {
4960:           for (b = 0; b < fdof; b++) {
4961:             ncSet = fcSet = PETSC_FALSE;
4962:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4963:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4964:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4965:           }
4966:         } else {
4967:           for (b = 0; b < fdof; b++) {
4968:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4969:               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4970:               ++cind;
4971:             }
4972:           }
4973:         }
4974:       } else {
4975:         if (comps) {
4976:           for (b = 0; b < fdof; b++) {
4977:             ncSet = fcSet = PETSC_FALSE;
4978:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4979:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4980:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4981:           }
4982:         } else {
4983:           for (b = 0; b < fdof; b++) {
4984:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4985:               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4986:               ++cind;
4987:             }
4988:           }
4989:         }
4990:       }
4991:     }
4992:   }
4993:   *offset += fdof;
4994:   return(0);
4995: }

4997: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4998: {
4999:   PetscScalar    *array;
5000:   const PetscInt *cone, *coneO;
5001:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
5002:   PetscErrorCode  ierr;

5005:   PetscSectionGetChart(section, &pStart, &pEnd);
5006:   DMPlexGetConeSize(dm, point, &numPoints);
5007:   DMPlexGetCone(dm, point, &cone);
5008:   DMPlexGetConeOrientation(dm, point, &coneO);
5009:   VecGetArray(v, &array);
5010:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
5011:     const PetscInt cp = !p ? point : cone[p-1];
5012:     const PetscInt o  = !p ? 0     : coneO[p-1];

5014:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
5015:     PetscSectionGetDof(section, cp, &dof);
5016:     /* ADD_VALUES */
5017:     {
5018:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5019:       PetscScalar    *a;
5020:       PetscInt        cdof, coff, cind = 0, k;

5022:       PetscSectionGetConstraintDof(section, cp, &cdof);
5023:       PetscSectionGetOffset(section, cp, &coff);
5024:       a    = &array[coff];
5025:       if (!cdof) {
5026:         if (o >= 0) {
5027:           for (k = 0; k < dof; ++k) {
5028:             a[k] += values[off+k];
5029:           }
5030:         } else {
5031:           for (k = 0; k < dof; ++k) {
5032:             a[k] += values[off+dof-k-1];
5033:           }
5034:         }
5035:       } else {
5036:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
5037:         if (o >= 0) {
5038:           for (k = 0; k < dof; ++k) {
5039:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5040:             a[k] += values[off+k];
5041:           }
5042:         } else {
5043:           for (k = 0; k < dof; ++k) {
5044:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5045:             a[k] += values[off+dof-k-1];
5046:           }
5047:         }
5048:       }
5049:     }
5050:   }
5051:   VecRestoreArray(v, &array);
5052:   return(0);
5053: }

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

5058:   Not collective

5060:   Input Parameters:
5061: + dm - The DM
5062: . section - The section describing the layout in v, or NULL to use the default section
5063: . v - The local vector
5064: . point - The point in the DM
5065: . values - The array of values
5066: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
5067:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

5072:   Level: intermediate

5074: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
5075: @*/
5076: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5077: {
5078:   PetscSection    clSection;
5079:   IS              clPoints;
5080:   PetscScalar    *array;
5081:   PetscInt       *points = NULL;
5082:   const PetscInt *clp, *clperm;
5083:   PetscInt        depth, numFields, numPoints, p;
5084:   PetscErrorCode  ierr;

5088:   if (!section) {DMGetLocalSection(dm, &section);}
5091:   DMPlexGetDepth(dm, &depth);
5092:   PetscSectionGetNumFields(section, &numFields);
5093:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
5094:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
5095:     return(0);
5096:   }
5097:   /* Get points */
5098:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5099:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5100:   /* Get array */
5101:   VecGetArray(v, &array);
5102:   /* Get values */
5103:   if (numFields > 0) {
5104:     PetscInt offset = 0, f;
5105:     for (f = 0; f < numFields; ++f) {
5106:       const PetscInt    **perms = NULL;
5107:       const PetscScalar **flips = NULL;

5109:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5110:       switch (mode) {
5111:       case INSERT_VALUES:
5112:         for (p = 0; p < numPoints; p++) {
5113:           const PetscInt    point = points[2*p];
5114:           const PetscInt    *perm = perms ? perms[p] : NULL;
5115:           const PetscScalar *flip = flips ? flips[p] : NULL;
5116:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
5117:         } break;
5118:       case INSERT_ALL_VALUES:
5119:         for (p = 0; p < numPoints; p++) {
5120:           const PetscInt    point = points[2*p];
5121:           const PetscInt    *perm = perms ? perms[p] : NULL;
5122:           const PetscScalar *flip = flips ? flips[p] : NULL;
5123:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
5124:         } break;
5125:       case INSERT_BC_VALUES:
5126:         for (p = 0; p < numPoints; p++) {
5127:           const PetscInt    point = points[2*p];
5128:           const PetscInt    *perm = perms ? perms[p] : NULL;
5129:           const PetscScalar *flip = flips ? flips[p] : NULL;
5130:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
5131:         } break;
5132:       case ADD_VALUES:
5133:         for (p = 0; p < numPoints; p++) {
5134:           const PetscInt    point = points[2*p];
5135:           const PetscInt    *perm = perms ? perms[p] : NULL;
5136:           const PetscScalar *flip = flips ? flips[p] : NULL;
5137:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
5138:         } break;
5139:       case ADD_ALL_VALUES:
5140:         for (p = 0; p < numPoints; p++) {
5141:           const PetscInt    point = points[2*p];
5142:           const PetscInt    *perm = perms ? perms[p] : NULL;
5143:           const PetscScalar *flip = flips ? flips[p] : NULL;
5144:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
5145:         } break;
5146:       case ADD_BC_VALUES:
5147:         for (p = 0; p < numPoints; p++) {
5148:           const PetscInt    point = points[2*p];
5149:           const PetscInt    *perm = perms ? perms[p] : NULL;
5150:           const PetscScalar *flip = flips ? flips[p] : NULL;
5151:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
5152:         } break;
5153:       default:
5154:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5155:       }
5156:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5157:     }
5158:   } else {
5159:     PetscInt dof, off;
5160:     const PetscInt    **perms = NULL;
5161:     const PetscScalar **flips = NULL;

5163:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
5164:     switch (mode) {
5165:     case INSERT_VALUES:
5166:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5167:         const PetscInt    point = points[2*p];
5168:         const PetscInt    *perm = perms ? perms[p] : NULL;
5169:         const PetscScalar *flip = flips ? flips[p] : NULL;
5170:         PetscSectionGetDof(section, point, &dof);
5171:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
5172:       } break;
5173:     case INSERT_ALL_VALUES:
5174:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5175:         const PetscInt    point = points[2*p];
5176:         const PetscInt    *perm = perms ? perms[p] : NULL;
5177:         const PetscScalar *flip = flips ? flips[p] : NULL;
5178:         PetscSectionGetDof(section, point, &dof);
5179:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
5180:       } break;
5181:     case INSERT_BC_VALUES:
5182:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5183:         const PetscInt    point = points[2*p];
5184:         const PetscInt    *perm = perms ? perms[p] : NULL;
5185:         const PetscScalar *flip = flips ? flips[p] : NULL;
5186:         PetscSectionGetDof(section, point, &dof);
5187:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
5188:       } break;
5189:     case ADD_VALUES:
5190:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5191:         const PetscInt    point = points[2*p];
5192:         const PetscInt    *perm = perms ? perms[p] : NULL;
5193:         const PetscScalar *flip = flips ? flips[p] : NULL;
5194:         PetscSectionGetDof(section, point, &dof);
5195:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
5196:       } break;
5197:     case ADD_ALL_VALUES:
5198:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5199:         const PetscInt    point = points[2*p];
5200:         const PetscInt    *perm = perms ? perms[p] : NULL;
5201:         const PetscScalar *flip = flips ? flips[p] : NULL;
5202:         PetscSectionGetDof(section, point, &dof);
5203:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
5204:       } break;
5205:     case ADD_BC_VALUES:
5206:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5207:         const PetscInt    point = points[2*p];
5208:         const PetscInt    *perm = perms ? perms[p] : NULL;
5209:         const PetscScalar *flip = flips ? flips[p] : NULL;
5210:         PetscSectionGetDof(section, point, &dof);
5211:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
5212:       } break;
5213:     default:
5214:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5215:     }
5216:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
5217:   }
5218:   /* Cleanup points */
5219:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5220:   /* Cleanup array */
5221:   VecRestoreArray(v, &array);
5222:   return(0);
5223: }

5225: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
5226: {
5227:   PetscSection      clSection;
5228:   IS                clPoints;
5229:   PetscScalar       *array;
5230:   PetscInt          *points = NULL;
5231:   const PetscInt    *clp, *clperm;
5232:   PetscInt          numFields, numPoints, p;
5233:   PetscInt          offset = 0, f;
5234:   PetscErrorCode    ierr;

5238:   if (!section) {DMGetLocalSection(dm, &section);}
5241:   PetscSectionGetNumFields(section, &numFields);
5242:   /* Get points */
5243:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5244:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5245:   /* Get array */
5246:   VecGetArray(v, &array);
5247:   /* Get values */
5248:   for (f = 0; f < numFields; ++f) {
5249:     const PetscInt    **perms = NULL;
5250:     const PetscScalar **flips = NULL;

5252:     if (!fieldActive[f]) {
5253:       for (p = 0; p < numPoints*2; p += 2) {
5254:         PetscInt fdof;
5255:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
5256:         offset += fdof;
5257:       }
5258:       continue;
5259:     }
5260:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5261:     switch (mode) {
5262:     case INSERT_VALUES:
5263:       for (p = 0; p < numPoints; p++) {
5264:         const PetscInt    point = points[2*p];
5265:         const PetscInt    *perm = perms ? perms[p] : NULL;
5266:         const PetscScalar *flip = flips ? flips[p] : NULL;
5267:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
5268:       } break;
5269:     case INSERT_ALL_VALUES:
5270:       for (p = 0; p < numPoints; p++) {
5271:         const PetscInt    point = points[2*p];
5272:         const PetscInt    *perm = perms ? perms[p] : NULL;
5273:         const PetscScalar *flip = flips ? flips[p] : NULL;
5274:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
5275:         } break;
5276:     case INSERT_BC_VALUES:
5277:       for (p = 0; p < numPoints; p++) {
5278:         const PetscInt    point = points[2*p];
5279:         const PetscInt    *perm = perms ? perms[p] : NULL;
5280:         const PetscScalar *flip = flips ? flips[p] : NULL;
5281:         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
5282:       } break;
5283:     case ADD_VALUES:
5284:       for (p = 0; p < numPoints; p++) {
5285:         const PetscInt    point = points[2*p];
5286:         const PetscInt    *perm = perms ? perms[p] : NULL;
5287:         const PetscScalar *flip = flips ? flips[p] : NULL;
5288:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
5289:       } break;
5290:     case ADD_ALL_VALUES:
5291:       for (p = 0; p < numPoints; p++) {
5292:         const PetscInt    point = points[2*p];
5293:         const PetscInt    *perm = perms ? perms[p] : NULL;
5294:         const PetscScalar *flip = flips ? flips[p] : NULL;
5295:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
5296:       } break;
5297:     default:
5298:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5299:     }
5300:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
5301:   }
5302:   /* Cleanup points */
5303:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5304:   /* Cleanup array */
5305:   VecRestoreArray(v, &array);
5306:   return(0);
5307: }

5309: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
5310: {
5311:   PetscMPIInt    rank;
5312:   PetscInt       i, j;

5316:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
5317:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
5318:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
5319:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
5320:   numCIndices = numCIndices ? numCIndices : numRIndices;
5321:   for (i = 0; i < numRIndices; i++) {
5322:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
5323:     for (j = 0; j < numCIndices; j++) {
5324: #if defined(PETSC_USE_COMPLEX)
5325:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
5326: #else
5327:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
5328: #endif
5329:     }
5330:     PetscViewerASCIIPrintf(viewer, "\n");
5331:   }
5332:   return(0);
5333: }

5335: /*
5336:   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array

5338:   Input Parameters:
5339: + section - The section for this data layout
5340: . point   - The point contributing dofs with these indices
5341: . off     - The global offset of this point
5342: . loff    - The local offset of each field
5343: . setBC   - The flag determining whether to include indices of bounsary values
5344: . perm    - A permutation of the dofs on this point, or NULL
5345: - indperm - A permutation of the entire indices array, or NULL

5347:   Output Parameter:
5348: . indices - Indices for dofs on this point

5350:   Level: developer

5352:   Note: The indices could be local or global, depending on the value of 'off'.
5353: */
5354: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
5355: {
5356:   PetscInt        dof;   /* The number of unknowns on this point */
5357:   PetscInt        cdof;  /* The number of constraints on this point */
5358:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5359:   PetscInt        cind = 0, k;
5360:   PetscErrorCode  ierr;

5363:   PetscSectionGetDof(section, point, &dof);
5364:   PetscSectionGetConstraintDof(section, point, &cdof);
5365:   if (!cdof || setBC) {
5366:     for (k = 0; k < dof; ++k) {
5367:       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5368:       const PetscInt ind    = indperm ? indperm[preind] : preind;

5370:       indices[ind] = off + k;
5371:     }
5372:   } else {
5373:     PetscSectionGetConstraintIndices(section, point, &cdofs);
5374:     for (k = 0; k < dof; ++k) {
5375:       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5376:       const PetscInt ind    = indperm ? indperm[preind] : preind;

5378:       if ((cind < cdof) && (k == cdofs[cind])) {
5379:         /* Insert check for returning constrained indices */
5380:         indices[ind] = -(off+k+1);
5381:         ++cind;
5382:       } else {
5383:         indices[ind] = off+k-cind;
5384:       }
5385:     }
5386:   }
5387:   *loff += dof;
5388:   return(0);
5389: }

5391: /*
5392:   This version only believes the point offset from the globalSection

5394:  . off - The global offset of this point
5395: */
5396: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5397: {
5398:   PetscInt       numFields, foff, f;

5402:   PetscSectionGetNumFields(section, &numFields);
5403:   for (f = 0, foff = 0; f < numFields; ++f) {
5404:     PetscInt        fdof, cfdof;
5405:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5406:     PetscInt        cind = 0, b;
5407:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5409:     PetscSectionGetFieldDof(section, point, f, &fdof);
5410:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5411:     if (!cfdof || setBC) {
5412:       for (b = 0; b < fdof; ++b) {
5413:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5414:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5416:         indices[ind] = off+foff+b;
5417:       }
5418:     } else {
5419:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5420:       for (b = 0; b < fdof; ++b) {
5421:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5422:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5424:         if ((cind < cfdof) && (b == fcdofs[cind])) {
5425:           indices[ind] = -(off+foff+b+1);
5426:           ++cind;
5427:         } else {
5428:           indices[ind] = off+foff+b-cind;
5429:         }
5430:       }
5431:     }
5432:     foff     += (setBC ? fdof : (fdof - cfdof));
5433:     foffs[f] += fdof;
5434:   }
5435:   return(0);
5436: }

5438: /*
5439:   This version believes the globalSection offsets for each field, rather than just the point offset

5441:  . foffs - The offset into 'indices' for each field, since it is segregated by field
5442: */
5443: PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5444: {
5445:   PetscInt       numFields, foff, f;

5449:   PetscSectionGetNumFields(section, &numFields);
5450:   for (f = 0; f < numFields; ++f) {
5451:     PetscInt        fdof, cfdof;
5452:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5453:     PetscInt        cind = 0, b;
5454:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5456:     PetscSectionGetFieldDof(section, point, f, &fdof);
5457:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5458:     PetscSectionGetFieldOffset(globalSection, point, f, &foff);
5459:     if (!cfdof || setBC) {
5460:       for (b = 0; b < fdof; ++b) {
5461:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5462:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5464:         indices[ind] = foff+b;
5465:       }
5466:     } else {
5467:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5468:       for (b = 0; b < fdof; ++b) {
5469:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5470:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5472:         if ((cind < cfdof) && (b == fcdofs[cind])) {
5473:           indices[ind] = -(foff+b+1);
5474:           ++cind;
5475:         } else {
5476:           indices[ind] = foff+b-cind;
5477:         }
5478:       }
5479:     }
5480:     foffs[f] += fdof;
5481:   }
5482:   return(0);
5483: }

5485: 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)
5486: {
5487:   Mat             cMat;
5488:   PetscSection    aSec, cSec;
5489:   IS              aIS;
5490:   PetscInt        aStart = -1, aEnd = -1;
5491:   const PetscInt  *anchors;
5492:   PetscInt        numFields, f, p, q, newP = 0;
5493:   PetscInt        newNumPoints = 0, newNumIndices = 0;
5494:   PetscInt        *newPoints, *indices, *newIndices;
5495:   PetscInt        maxAnchor, maxDof;
5496:   PetscInt        newOffsets[32];
5497:   PetscInt        *pointMatOffsets[32];
5498:   PetscInt        *newPointOffsets[32];
5499:   PetscScalar     *pointMat[32];
5500:   PetscScalar     *newValues=NULL,*tmpValues;
5501:   PetscBool       anyConstrained = PETSC_FALSE;
5502:   PetscErrorCode  ierr;

5507:   PetscSectionGetNumFields(section, &numFields);

5509:   DMPlexGetAnchors(dm,&aSec,&aIS);
5510:   /* if there are point-to-point constraints */
5511:   if (aSec) {
5512:     PetscArrayzero(newOffsets, 32);
5513:     ISGetIndices(aIS,&anchors);
5514:     PetscSectionGetChart(aSec,&aStart,&aEnd);
5515:     /* figure out how many points are going to be in the new element matrix
5516:      * (we allow double counting, because it's all just going to be summed
5517:      * into the global matrix anyway) */
5518:     for (p = 0; p < 2*numPoints; p+=2) {
5519:       PetscInt b    = points[p];
5520:       PetscInt bDof = 0, bSecDof;

5522:       PetscSectionGetDof(section,b,&bSecDof);
5523:       if (!bSecDof) {
5524:         continue;
5525:       }
5526:       if (b >= aStart && b < aEnd) {
5527:         PetscSectionGetDof(aSec,b,&bDof);
5528:       }
5529:       if (bDof) {
5530:         /* this point is constrained */
5531:         /* it is going to be replaced by its anchors */
5532:         PetscInt bOff, q;

5534:         anyConstrained = PETSC_TRUE;
5535:         newNumPoints  += bDof;
5536:         PetscSectionGetOffset(aSec,b,&bOff);
5537:         for (q = 0; q < bDof; q++) {
5538:           PetscInt a = anchors[bOff + q];
5539:           PetscInt aDof;

5541:           PetscSectionGetDof(section,a,&aDof);
5542:           newNumIndices += aDof;
5543:           for (f = 0; f < numFields; ++f) {
5544:             PetscInt fDof;

5546:             PetscSectionGetFieldDof(section, a, f, &fDof);
5547:             newOffsets[f+1] += fDof;
5548:           }
5549:         }
5550:       }
5551:       else {
5552:         /* this point is not constrained */
5553:         newNumPoints++;
5554:         newNumIndices += bSecDof;
5555:         for (f = 0; f < numFields; ++f) {
5556:           PetscInt fDof;

5558:           PetscSectionGetFieldDof(section, b, f, &fDof);
5559:           newOffsets[f+1] += fDof;
5560:         }
5561:       }
5562:     }
5563:   }
5564:   if (!anyConstrained) {
5565:     if (outNumPoints)  *outNumPoints  = 0;
5566:     if (outNumIndices) *outNumIndices = 0;
5567:     if (outPoints)     *outPoints     = NULL;
5568:     if (outValues)     *outValues     = NULL;
5569:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5570:     return(0);
5571:   }

5573:   if (outNumPoints)  *outNumPoints  = newNumPoints;
5574:   if (outNumIndices) *outNumIndices = newNumIndices;

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

5578:   if (!outPoints && !outValues) {
5579:     if (offsets) {
5580:       for (f = 0; f <= numFields; f++) {
5581:         offsets[f] = newOffsets[f];
5582:       }
5583:     }
5584:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5585:     return(0);
5586:   }

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

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

5592:   /* workspaces */
5593:   if (numFields) {
5594:     for (f = 0; f < numFields; f++) {
5595:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5596:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5597:     }
5598:   }
5599:   else {
5600:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5601:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5602:   }

5604:   /* get workspaces for the point-to-point matrices */
5605:   if (numFields) {
5606:     PetscInt totalOffset, totalMatOffset;

5608:     for (p = 0; p < numPoints; p++) {
5609:       PetscInt b    = points[2*p];
5610:       PetscInt bDof = 0, bSecDof;

5612:       PetscSectionGetDof(section,b,&bSecDof);
5613:       if (!bSecDof) {
5614:         for (f = 0; f < numFields; f++) {
5615:           newPointOffsets[f][p + 1] = 0;
5616:           pointMatOffsets[f][p + 1] = 0;
5617:         }
5618:         continue;
5619:       }
5620:       if (b >= aStart && b < aEnd) {
5621:         PetscSectionGetDof(aSec, b, &bDof);
5622:       }
5623:       if (bDof) {
5624:         for (f = 0; f < numFields; f++) {
5625:           PetscInt fDof, q, bOff, allFDof = 0;

5627:           PetscSectionGetFieldDof(section, b, f, &fDof);
5628:           PetscSectionGetOffset(aSec, b, &bOff);
5629:           for (q = 0; q < bDof; q++) {
5630:             PetscInt a = anchors[bOff + q];
5631:             PetscInt aFDof;

5633:             PetscSectionGetFieldDof(section, a, f, &aFDof);
5634:             allFDof += aFDof;
5635:           }
5636:           newPointOffsets[f][p+1] = allFDof;
5637:           pointMatOffsets[f][p+1] = fDof * allFDof;
5638:         }
5639:       }
5640:       else {
5641:         for (f = 0; f < numFields; f++) {
5642:           PetscInt fDof;

5644:           PetscSectionGetFieldDof(section, b, f, &fDof);
5645:           newPointOffsets[f][p+1] = fDof;
5646:           pointMatOffsets[f][p+1] = 0;
5647:         }
5648:       }
5649:     }
5650:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5651:       newPointOffsets[f][0] = totalOffset;
5652:       pointMatOffsets[f][0] = totalMatOffset;
5653:       for (p = 0; p < numPoints; p++) {
5654:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5655:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5656:       }
5657:       totalOffset    = newPointOffsets[f][numPoints];
5658:       totalMatOffset = pointMatOffsets[f][numPoints];
5659:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5660:     }
5661:   }
5662:   else {
5663:     for (p = 0; p < numPoints; p++) {
5664:       PetscInt b    = points[2*p];
5665:       PetscInt bDof = 0, bSecDof;

5667:       PetscSectionGetDof(section,b,&bSecDof);
5668:       if (!bSecDof) {
5669:         newPointOffsets[0][p + 1] = 0;
5670:         pointMatOffsets[0][p + 1] = 0;
5671:         continue;
5672:       }
5673:       if (b >= aStart && b < aEnd) {
5674:         PetscSectionGetDof(aSec, b, &bDof);
5675:       }
5676:       if (bDof) {
5677:         PetscInt bOff, q, allDof = 0;

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

5683:           PetscSectionGetDof(section, a, &aDof);
5684:           allDof += aDof;
5685:         }
5686:         newPointOffsets[0][p+1] = allDof;
5687:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5688:       }
5689:       else {
5690:         newPointOffsets[0][p+1] = bSecDof;
5691:         pointMatOffsets[0][p+1] = 0;
5692:       }
5693:     }
5694:     newPointOffsets[0][0] = 0;
5695:     pointMatOffsets[0][0] = 0;
5696:     for (p = 0; p < numPoints; p++) {
5697:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5698:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5699:     }
5700:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5701:   }

5703:   /* output arrays */
5704:   DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);

5706:   /* get the point-to-point matrices; construct newPoints */
5707:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5708:   PetscSectionGetMaxDof(section, &maxDof);
5709:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5710:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5711:   if (numFields) {
5712:     for (p = 0, newP = 0; p < numPoints; p++) {
5713:       PetscInt b    = points[2*p];
5714:       PetscInt o    = points[2*p+1];
5715:       PetscInt bDof = 0, bSecDof;

5717:       PetscSectionGetDof(section, b, &bSecDof);
5718:       if (!bSecDof) {
5719:         continue;
5720:       }
5721:       if (b >= aStart && b < aEnd) {
5722:         PetscSectionGetDof(aSec, b, &bDof);
5723:       }
5724:       if (bDof) {
5725:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5727:         fStart[0] = 0;
5728:         fEnd[0]   = 0;
5729:         for (f = 0; f < numFields; f++) {
5730:           PetscInt fDof;

5732:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5733:           fStart[f+1] = fStart[f] + fDof;
5734:           fEnd[f+1]   = fStart[f+1];
5735:         }
5736:         PetscSectionGetOffset(cSec, b, &bOff);
5737:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);

5739:         fAnchorStart[0] = 0;
5740:         fAnchorEnd[0]   = 0;
5741:         for (f = 0; f < numFields; f++) {
5742:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5744:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5745:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5746:         }
5747:         PetscSectionGetOffset(aSec, b, &bOff);
5748:         for (q = 0; q < bDof; q++) {
5749:           PetscInt a = anchors[bOff + q], aOff;

5751:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5752:           newPoints[2*(newP + q)]     = a;
5753:           newPoints[2*(newP + q) + 1] = 0;
5754:           PetscSectionGetOffset(section, a, &aOff);
5755:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);
5756:         }
5757:         newP += bDof;

5759:         if (outValues) {
5760:           /* get the point-to-point submatrix */
5761:           for (f = 0; f < numFields; f++) {
5762:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5763:           }
5764:         }
5765:       }
5766:       else {
5767:         newPoints[2 * newP]     = b;
5768:         newPoints[2 * newP + 1] = o;
5769:         newP++;
5770:       }
5771:     }
5772:   } else {
5773:     for (p = 0; p < numPoints; p++) {
5774:       PetscInt b    = points[2*p];
5775:       PetscInt o    = points[2*p+1];
5776:       PetscInt bDof = 0, bSecDof;

5778:       PetscSectionGetDof(section, b, &bSecDof);
5779:       if (!bSecDof) {
5780:         continue;
5781:       }
5782:       if (b >= aStart && b < aEnd) {
5783:         PetscSectionGetDof(aSec, b, &bDof);
5784:       }
5785:       if (bDof) {
5786:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5797:           newPoints[2*(newP + q)]     = a;
5798:           newPoints[2*(newP + q) + 1] = 0;
5799:           PetscSectionGetOffset(section, a, &aOff);
5800:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);
5801:         }
5802:         newP += bDof;

5804:         /* get the point-to-point submatrix */
5805:         if (outValues) {
5806:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5807:         }
5808:       }
5809:       else {
5810:         newPoints[2 * newP]     = b;
5811:         newPoints[2 * newP + 1] = o;
5812:         newP++;
5813:       }
5814:     }
5815:   }

5817:   if (outValues) {
5818:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5819:     PetscArrayzero(tmpValues,newNumIndices*numIndices);
5820:     /* multiply constraints on the right */
5821:     if (numFields) {
5822:       for (f = 0; f < numFields; f++) {
5823:         PetscInt oldOff = offsets[f];

5825:         for (p = 0; p < numPoints; p++) {
5826:           PetscInt cStart = newPointOffsets[f][p];
5827:           PetscInt b      = points[2 * p];
5828:           PetscInt c, r, k;
5829:           PetscInt dof;

5831:           PetscSectionGetFieldDof(section,b,f,&dof);
5832:           if (!dof) {
5833:             continue;
5834:           }
5835:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5836:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5837:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5839:             for (r = 0; r < numIndices; r++) {
5840:               for (c = 0; c < nCols; c++) {
5841:                 for (k = 0; k < dof; k++) {
5842:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5843:                 }
5844:               }
5845:             }
5846:           }
5847:           else {
5848:             /* copy this column as is */
5849:             for (r = 0; r < numIndices; r++) {
5850:               for (c = 0; c < dof; c++) {
5851:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5852:               }
5853:             }
5854:           }
5855:           oldOff += dof;
5856:         }
5857:       }
5858:     }
5859:     else {
5860:       PetscInt oldOff = 0;
5861:       for (p = 0; p < numPoints; p++) {
5862:         PetscInt cStart = newPointOffsets[0][p];
5863:         PetscInt b      = points[2 * p];
5864:         PetscInt c, r, k;
5865:         PetscInt dof;

5867:         PetscSectionGetDof(section,b,&dof);
5868:         if (!dof) {
5869:           continue;
5870:         }
5871:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5872:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5873:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5875:           for (r = 0; r < numIndices; r++) {
5876:             for (c = 0; c < nCols; c++) {
5877:               for (k = 0; k < dof; k++) {
5878:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5879:               }
5880:             }
5881:           }
5882:         }
5883:         else {
5884:           /* copy this column as is */
5885:           for (r = 0; r < numIndices; r++) {
5886:             for (c = 0; c < dof; c++) {
5887:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5888:             }
5889:           }
5890:         }
5891:         oldOff += dof;
5892:       }
5893:     }

5895:     if (multiplyLeft) {
5896:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5897:       PetscArrayzero(newValues,newNumIndices*newNumIndices);
5898:       /* multiply constraints transpose on the left */
5899:       if (numFields) {
5900:         for (f = 0; f < numFields; f++) {
5901:           PetscInt oldOff = offsets[f];

5903:           for (p = 0; p < numPoints; p++) {
5904:             PetscInt rStart = newPointOffsets[f][p];
5905:             PetscInt b      = points[2 * p];
5906:             PetscInt c, r, k;
5907:             PetscInt dof;

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

5914:               for (r = 0; r < nRows; r++) {
5915:                 for (c = 0; c < newNumIndices; c++) {
5916:                   for (k = 0; k < dof; k++) {
5917:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5918:                   }
5919:                 }
5920:               }
5921:             }
5922:             else {
5923:               /* copy this row as is */
5924:               for (r = 0; r < dof; r++) {
5925:                 for (c = 0; c < newNumIndices; c++) {
5926:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5927:                 }
5928:               }
5929:             }
5930:             oldOff += dof;
5931:           }
5932:         }
5933:       }
5934:       else {
5935:         PetscInt oldOff = 0;

5937:         for (p = 0; p < numPoints; p++) {
5938:           PetscInt rStart = newPointOffsets[0][p];
5939:           PetscInt b      = points[2 * p];
5940:           PetscInt c, r, k;
5941:           PetscInt dof;

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

5948:             for (r = 0; r < nRows; r++) {
5949:               for (c = 0; c < newNumIndices; c++) {
5950:                 for (k = 0; k < dof; k++) {
5951:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5952:                 }
5953:               }
5954:             }
5955:           }
5956:           else {
5957:             /* copy this row as is */
5958:             for (r = 0; r < dof; r++) {
5959:               for (c = 0; c < newNumIndices; c++) {
5960:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5961:               }
5962:             }
5963:           }
5964:           oldOff += dof;
5965:         }
5966:       }

5968:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5969:     }
5970:     else {
5971:       newValues = tmpValues;
5972:     }
5973:   }

5975:   /* clean up */
5976:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5977:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5979:   if (numFields) {
5980:     for (f = 0; f < numFields; f++) {
5981:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5982:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5983:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5984:     }
5985:   }
5986:   else {
5987:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5988:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5989:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5990:   }
5991:   ISRestoreIndices(aIS,&anchors);

5993:   /* output */
5994:   if (outPoints) {
5995:     *outPoints = newPoints;
5996:   }
5997:   else {
5998:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5999:   }
6000:   if (outValues) {
6001:     *outValues = newValues;
6002:   }
6003:   for (f = 0; f <= numFields; f++) {
6004:     offsets[f] = newOffsets[f];
6005:   }
6006:   return(0);
6007: }

6009: /*@C
6010:   DMPlexGetClosureIndices - Get the global indices for all local points in the closure of the given point

6012:   Not collective

6014:   Input Parameters:
6015: + dm - The DM
6016: . section - The section describing the local layout
6017: . globalSection - The section describing the parallel layout
6018: - point - The mesh point

6020:   Output parameters:
6021: + numIndices - The number of indices
6022: . indices - The indices
6023: - outOffsets - Field offset if not NULL

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

6027:   Level: advanced

6029: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
6030: @*/
6031: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
6032: {
6033:   PetscSection    clSection;
6034:   IS              clPoints;
6035:   const PetscInt *clp, *clperm;
6036:   const PetscInt  **perms[32] = {NULL};
6037:   PetscInt       *points = NULL, *pointsNew;
6038:   PetscInt        numPoints, numPointsNew;
6039:   PetscInt        offsets[32];
6040:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
6041:   PetscErrorCode  ierr;

6049:   PetscSectionGetNumFields(section, &Nf);
6050:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
6051:   PetscArrayzero(offsets, 32);
6052:   /* Get points in closure */
6053:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6054:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
6055:   /* Get number of indices and indices per field */
6056:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
6057:     PetscInt dof, fdof;

6059:     PetscSectionGetDof(section, points[p], &dof);
6060:     for (f = 0; f < Nf; ++f) {
6061:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
6062:       offsets[f+1] += fdof;
6063:     }
6064:     Nind += dof;
6065:   }
6066:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
6067:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
6068:   if (!Nf) offsets[1] = Nind;
6069:   /* Get dual space symmetries */
6070:   for (f = 0; f < PetscMax(1,Nf); f++) {
6071:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
6072:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
6073:   }
6074:   /* Correct for hanging node constraints */
6075:   {
6076:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
6077:     if (numPointsNew) {
6078:       for (f = 0; f < PetscMax(1,Nf); f++) {
6079:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
6080:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
6081:       }
6082:       for (f = 0; f < PetscMax(1,Nf); f++) {
6083:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
6084:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
6085:       }
6086:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6087:       numPoints = numPointsNew;
6088:       Nind      = NindNew;
6089:       points    = pointsNew;
6090:     }
6091:   }
6092:   /* Calculate indices */
6093:   DMGetWorkArray(dm, Nind, MPIU_INT, indices);
6094:   if (Nf) {
6095:     if (outOffsets) {
6096:       PetscInt f;

6098:       for (f = 0; f <= Nf; f++) {
6099:         outOffsets[f] = offsets[f];
6100:       }
6101:     }
6102:     for (p = 0; p < numPoints; p++) {
6103:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6104:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);
6105:     }
6106:   } else {
6107:     for (p = 0, off = 0; p < numPoints; p++) {
6108:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

6110:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6111:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, *indices);
6112:     }
6113:   }
6114:   /* Cleanup points */
6115:   for (f = 0; f < PetscMax(1,Nf); f++) {
6116:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
6117:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
6118:   }
6119:   if (numPointsNew) {
6120:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
6121:   } else {
6122:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6123:   }
6124:   if (numIndices) *numIndices = Nind;
6125:   return(0);
6126: }

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

6131:   Not collective

6133:   Input Parameters:
6134: + dm - The DM
6135: . section - The section describing the layout in v, or NULL to use the default section
6136: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
6137: . point - The mesh point
6138: . numIndices - The number of indices
6139: . indices - The indices
6140: - outOffsets - Field offset if not NULL

6142:   Level: advanced

6144: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
6145: @*/
6146: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
6147: {

6153:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
6154:   return(0);
6155: }

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

6160:   Not collective

6162:   Input Parameters:
6163: + dm - The DM
6164: . section - The section describing the layout in v, or NULL to use the default section
6165: . globalSection - The section describing the layout in v, or NULL to use the default global section
6166: . A - The matrix
6167: . point - The point in the DM
6168: . values - The array of values
6169: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

6174:   Level: intermediate

6176: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
6177: @*/
6178: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6179: {
6180:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
6181:   PetscSection        clSection;
6182:   IS                  clPoints;
6183:   PetscInt           *points = NULL, *newPoints;
6184:   const PetscInt     *clp, *clperm;
6185:   PetscInt           *indices;
6186:   PetscInt            offsets[32];
6187:   const PetscInt    **perms[32] = {NULL};
6188:   const PetscScalar **flips[32] = {NULL};
6189:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
6190:   PetscScalar        *valCopy = NULL;
6191:   PetscScalar        *newValues;
6192:   PetscErrorCode      ierr;

6196:   if (!section) {DMGetLocalSection(dm, &section);}
6198:   if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
6201:   PetscSectionGetNumFields(section, &numFields);
6202:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6203:   PetscArrayzero(offsets, 32);
6204:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
6205:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6206:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
6207:     PetscInt fdof;

6209:     PetscSectionGetDof(section, points[p], &dof);
6210:     for (f = 0; f < numFields; ++f) {
6211:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
6212:       offsets[f+1] += fdof;
6213:     }
6214:     numIndices += dof;
6215:   }
6216:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

6230:         if (!numFields) {
6231:           PetscSectionGetDof(section,point,&fdof);
6232:         } else {
6233:           PetscSectionGetFieldDof(section,point,f,&fdof);
6234:         }
6235:         if (flip) {
6236:           PetscInt i, j, k;

6238:           if (!valCopy) {
6239:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6240:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
6241:             values = valCopy;
6242:           }
6243:           for (i = 0; i < fdof; i++) {
6244:             PetscScalar fval = flip[i];

6246:             for (k = 0; k < numIndices; k++) {
6247:               valCopy[numIndices * (foffset + i) + k] *= fval;
6248:               valCopy[numIndices * k + (foffset + i)] *= fval;
6249:             }
6250:           }
6251:         }
6252:         foffset += fdof;
6253:       }
6254:     }
6255:   }
6256:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
6257:   if (newNumPoints) {
6258:     if (valCopy) {
6259:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6260:     }
6261:     for (f = 0; f < PetscMax(1,numFields); f++) {
6262:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6263:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6264:     }
6265:     for (f = 0; f < PetscMax(1,numFields); f++) {
6266:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
6267:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
6268:     }
6269:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6270:     numPoints  = newNumPoints;
6271:     numIndices = newNumIndices;
6272:     points     = newPoints;
6273:     values     = newValues;
6274:   }
6275:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
6276:   if (numFields) {
6277:     PetscBool useFieldOffsets;

6279:     PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
6280:     if (useFieldOffsets) {
6281:       for (p = 0; p < numPoints; p++) {
6282:         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, clperm, indices);
6283:       }
6284:     } else {
6285:       for (p = 0; p < numPoints; p++) {
6286:         PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6287:         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices);
6288:       }
6289:     }
6290:   } else {
6291:     for (p = 0, off = 0; p < numPoints; p++) {
6292:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
6293:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
6294:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices);
6295:     }
6296:   }
6297:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
6298:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
6299:   if (mesh->printFEM > 1) {
6300:     PetscInt i;
6301:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
6302:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
6303:     PetscPrintf(PETSC_COMM_SELF, "\n");
6304:   }
6305:   if (ierr) {
6306:     PetscMPIInt    rank;
6307:     PetscErrorCode ierr2;

6309:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6310:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6311:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
6312:     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
6313: 
6314:   }
6315:   for (f = 0; f < PetscMax(1,numFields); f++) {
6316:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
6317:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
6318:   }
6319:   if (newNumPoints) {
6320:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
6321:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
6322:   }
6323:   else {
6324:     if (valCopy) {
6325:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
6326:     }
6327:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
6328:   }
6329:   DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
6330:   return(0);
6331: }

6333: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6334: {
6335:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
6336:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
6337:   PetscInt       *cpoints = NULL;
6338:   PetscInt       *findices, *cindices;
6339:   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
6340:   PetscInt        foffsets[32], coffsets[32];
6341:   CellRefiner     cellRefiner;
6342:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6343:   PetscErrorCode  ierr;

6348:   if (!fsection) {DMGetLocalSection(dmf, &fsection);}
6350:   if (!csection) {DMGetLocalSection(dmc, &csection);}
6352:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6354:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6357:   PetscSectionGetNumFields(fsection, &numFields);
6358:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6359:   PetscArrayzero(foffsets, 32);
6360:   PetscArrayzero(coffsets, 32);
6361:   /* Column indices */
6362:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6363:   maxFPoints = numCPoints;
6364:   /* Compress out points not in the section */
6365:   /*   TODO: Squeeze out points with 0 dof as well */
6366:   PetscSectionGetChart(csection, &pStart, &pEnd);
6367:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6368:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6369:       cpoints[q*2]   = cpoints[p];
6370:       cpoints[q*2+1] = cpoints[p+1];
6371:       ++q;
6372:     }
6373:   }
6374:   numCPoints = q;
6375:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6376:     PetscInt fdof;

6378:     PetscSectionGetDof(csection, cpoints[p], &dof);
6379:     if (!dof) continue;
6380:     for (f = 0; f < numFields; ++f) {
6381:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6382:       coffsets[f+1] += fdof;
6383:     }
6384:     numCIndices += dof;
6385:   }
6386:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6387:   /* Row indices */
6388:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6389:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6390:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6391:   for (r = 0, q = 0; r < numSubcells; ++r) {
6392:     /* TODO Map from coarse to fine cells */
6393:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6394:     /* Compress out points not in the section */
6395:     PetscSectionGetChart(fsection, &pStart, &pEnd);
6396:     for (p = 0; p < numFPoints*2; p += 2) {
6397:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6398:         PetscSectionGetDof(fsection, fpoints[p], &dof);
6399:         if (!dof) continue;
6400:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6401:         if (s < q) continue;
6402:         ftotpoints[q*2]   = fpoints[p];
6403:         ftotpoints[q*2+1] = fpoints[p+1];
6404:         ++q;
6405:       }
6406:     }
6407:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6408:   }
6409:   numFPoints = q;
6410:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6411:     PetscInt fdof;

6413:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6414:     if (!dof) continue;
6415:     for (f = 0; f < numFields; ++f) {
6416:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6417:       foffsets[f+1] += fdof;
6418:     }
6419:     numFIndices += dof;
6420:   }
6421:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

6423:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6424:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6425:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6426:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6427:   if (numFields) {
6428:     const PetscInt **permsF[32] = {NULL};
6429:     const PetscInt **permsC[32] = {NULL};

6431:     for (f = 0; f < numFields; f++) {
6432:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6433:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6434:     }
6435:     for (p = 0; p < numFPoints; p++) {
6436:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6437:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6438:     }
6439:     for (p = 0; p < numCPoints; p++) {
6440:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6441:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6442:     }
6443:     for (f = 0; f < numFields; f++) {
6444:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6445:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6446:     }
6447:   } else {
6448:     const PetscInt **permsF = NULL;
6449:     const PetscInt **permsC = NULL;

6451:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6452:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6453:     for (p = 0, off = 0; p < numFPoints; p++) {
6454:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6456:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6457:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6458:     }
6459:     for (p = 0, off = 0; p < numCPoints; p++) {
6460:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6462:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6463:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6464:     }
6465:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6466:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6467:   }
6468:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
6469:   /* TODO: flips */
6470:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6471:   if (ierr) {
6472:     PetscMPIInt    rank;
6473:     PetscErrorCode ierr2;

6475:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6476:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6477:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6478:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6479:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6480: 
6481:   }
6482:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6483:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6484:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6485:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6486:   return(0);
6487: }

6489: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6490: {
6491:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
6492:   PetscInt      *cpoints = NULL;
6493:   PetscInt       foffsets[32], coffsets[32];
6494:   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
6495:   CellRefiner    cellRefiner;
6496:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

6502:   if (!fsection) {DMGetLocalSection(dmf, &fsection);}
6504:   if (!csection) {DMGetLocalSection(dmc, &csection);}
6506:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6508:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6510:   PetscSectionGetNumFields(fsection, &numFields);
6511:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6512:   PetscArrayzero(foffsets, 32);
6513:   PetscArrayzero(coffsets, 32);
6514:   /* Column indices */
6515:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6516:   maxFPoints = numCPoints;
6517:   /* Compress out points not in the section */
6518:   /*   TODO: Squeeze out points with 0 dof as well */
6519:   PetscSectionGetChart(csection, &pStart, &pEnd);
6520:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6521:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6522:       cpoints[q*2]   = cpoints[p];
6523:       cpoints[q*2+1] = cpoints[p+1];
6524:       ++q;
6525:     }
6526:   }
6527:   numCPoints = q;
6528:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6529:     PetscInt fdof;

6531:     PetscSectionGetDof(csection, cpoints[p], &dof);
6532:     if (!dof) continue;
6533:     for (f = 0; f < numFields; ++f) {
6534:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6535:       coffsets[f+1] += fdof;
6536:     }
6537:     numCIndices += dof;
6538:   }
6539:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6540:   /* Row indices */
6541:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6542:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6543:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6544:   for (r = 0, q = 0; r < numSubcells; ++r) {
6545:     /* TODO Map from coarse to fine cells */
6546:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6547:     /* Compress out points not in the section */
6548:     PetscSectionGetChart(fsection, &pStart, &pEnd);
6549:     for (p = 0; p < numFPoints*2; p += 2) {
6550:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6551:         PetscSectionGetDof(fsection, fpoints[p], &dof);
6552:         if (!dof) continue;
6553:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6554:         if (s < q) continue;
6555:         ftotpoints[q*2]   = fpoints[p];
6556:         ftotpoints[q*2+1] = fpoints[p+1];
6557:         ++q;
6558:       }
6559:     }
6560:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6561:   }
6562:   numFPoints = q;
6563:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6564:     PetscInt fdof;

6566:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6567:     if (!dof) continue;
6568:     for (f = 0; f < numFields; ++f) {
6569:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6570:       foffsets[f+1] += fdof;
6571:     }
6572:     numFIndices += dof;
6573:   }
6574:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

6582:     for (f = 0; f < numFields; f++) {
6583:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6584:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6585:     }
6586:     for (p = 0; p < numFPoints; p++) {
6587:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6588:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6589:     }
6590:     for (p = 0; p < numCPoints; p++) {
6591:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6592:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6593:     }
6594:     for (f = 0; f < numFields; f++) {
6595:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6596:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6597:     }
6598:   } else {
6599:     const PetscInt **permsF = NULL;
6600:     const PetscInt **permsC = NULL;

6602:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6603:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6604:     for (p = 0, off = 0; p < numFPoints; p++) {
6605:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6607:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6608:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6609:     }
6610:     for (p = 0, off = 0; p < numCPoints; p++) {
6611:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6613:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6614:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6615:     }
6616:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6617:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6618:   }
6619:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6620:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6621:   return(0);
6622: }

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

6627:   Input Parameter:
6628: . dm - The DMPlex object

6630:   Output Parameters:
6631: + cMax - The first hybrid cell
6632: . fMax - The first hybrid face
6633: . eMax - The first hybrid edge
6634: - vMax - The first hybrid vertex

6636:   Level: developer

6638: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6639: @*/
6640: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6641: {
6642:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6643:   PetscInt       dim;

6648:   DMGetDimension(dm, &dim);
6649:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6650:   if (cMax) *cMax = mesh->hybridPointMax[dim];
6651:   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6652:   if (eMax) *eMax = mesh->hybridPointMax[1];
6653:   if (vMax) *vMax = mesh->hybridPointMax[0];
6654:   return(0);
6655: }

6657: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6658: {
6659:   IS             is, his;
6660:   PetscInt       first = 0, stride;
6661:   PetscBool      isStride;

6665:   DMLabelGetStratumIS(depthLabel, d, &is);
6666:   PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6667:   if (isStride) {ISStrideGetInfo(is, &first, &stride);}
6668:   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6669:   ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6670:   DMLabelSetStratumIS(dimLabel, d, his);
6671:   ISDestroy(&his);
6672:   ISDestroy(&is);
6673:   return(0);
6674: }

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

6679:   Input Parameters:
6680: + dm   - The DMPlex object
6681: . cMax - The first hybrid cell
6682: . fMax - The first hybrid face
6683: . eMax - The first hybrid edge
6684: - vMax - The first hybrid vertex

6686:   Level: developer

6688: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6689: @*/
6690: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6691: {
6692:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6693:   PetscInt       dim;

6698:   DMGetDimension(dm, &dim);
6699:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6700:   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6701:   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6702:   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6703:   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6704:   return(0);
6705: }

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

6710:   Input Parameter:
6711: . dm   - The DMPlex object

6713:   Output Parameter:
6714: . cellHeight - The height of a cell

6716:   Level: developer

6718: .seealso DMPlexSetVTKCellHeight()
6719: @*/
6720: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6721: {
6722:   DM_Plex *mesh = (DM_Plex*) dm->data;

6727:   *cellHeight = mesh->vtkCellHeight;
6728:   return(0);
6729: }

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

6734:   Input Parameters:
6735: + dm   - The DMPlex object
6736: - cellHeight - The height of a cell

6738:   Level: developer

6740: .seealso DMPlexGetVTKCellHeight()
6741: @*/
6742: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6743: {
6744:   DM_Plex *mesh = (DM_Plex*) dm->data;

6748:   mesh->vtkCellHeight = cellHeight;
6749:   return(0);
6750: }

6752: /*@
6753:   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions

6755:   Input Parameter:
6756: . dm - The DMPlex object

6758:   Output Parameters:
6759: + gcStart - The first ghost cell, or NULL
6760: - gcEnd   - The upper bound on ghost cells, or NULL

6762:   Level: advanced

6764: .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds()
6765: @*/
6766: PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
6767: {
6768:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6769:   PetscInt       dim;

6774:   DMGetDimension(dm, &dim);
6775:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6777:   if (gcEnd)   {
6779:     if (mesh->ghostCellStart >= 0) {DMPlexGetHeightStratum(dm, 0, NULL, gcEnd);}
6780:     else                           {*gcEnd = -1;}
6781:   }
6782:   return(0);
6783: }

6785: /*@
6786:   DMPlexSetGhostCellStratum - Set the range of cells which are used to enforce FV boundary conditions

6788:   Input Parameters:
6789: + dm      - The DMPlex object
6790: . gcStart - The first ghost cell, or PETSC_DETERMINE
6791: - gcEnd   - The upper bound on ghost cells, or PETSC_DETERMINE

6793:   Level: advanced

6795:   Note: This is not usually called directly by a user.

6797: .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum(), DMPlexSetHybridBounds()
6798: @*/
6799: PetscErrorCode DMPlexSetGhostCellStratum(DM dm, PetscInt gcStart, PetscInt gcEnd)
6800: {
6801:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6802:   PetscInt       dim;

6807:   DMGetDimension(dm, &dim);
6808:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6809:   mesh->ghostCellStart = gcStart;
6810:   if (gcEnd >= 0) {
6811:     PetscInt cEnd;
6812:     DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);
6813:     if (gcEnd != cEnd) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Ghost cells must appear at the end of the cell range, but gcEnd %D is not equal to cEnd %D", gcEnd, cEnd);
6814:   }
6815:   return(0);
6816: }

6818: /*@
6819:   DMPlexGetInteriorCellStratum - Get the range of cells which are neither hybrid nor ghost FV cells

6821:   Input Parameter:
6822: . dm - The DMPlex object

6824:   Output Parameters:
6825: + cStartInterior - The first ghost cell
6826: - cEndInterior   - The upper bound on ghost cells

6828:   Level: developer

6830: .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds()
6831: @*/
6832: PetscErrorCode DMPlexGetInteriorCellStratum(DM dm, PetscInt *cStartInterior, PetscInt *cEndInterior)
6833: {
6834:   PetscInt       gcEnd, cMax;

6838:   DMPlexGetHeightStratum(dm, 0, cStartInterior, cEndInterior);
6839:   DMPlexGetGhostCellStratum(dm, &gcEnd, NULL);
6840:   *cEndInterior = gcEnd < 0 ? *cEndInterior : gcEnd;
6841:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6842:   *cEndInterior = cMax  < 0 ? *cEndInterior : cMax;
6843:   return(0);
6844: }

6846: /* We can easily have a form that takes an IS instead */
6847: PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6848: {
6849:   PetscSection   section, globalSection;
6850:   PetscInt      *numbers, p;

6854:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6855:   PetscSectionSetChart(section, pStart, pEnd);
6856:   for (p = pStart; p < pEnd; ++p) {
6857:     PetscSectionSetDof(section, p, 1);
6858:   }
6859:   PetscSectionSetUp(section);
6860:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6861:   PetscMalloc1(pEnd - pStart, &numbers);
6862:   for (p = pStart; p < pEnd; ++p) {
6863:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6864:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6865:     else                       numbers[p-pStart] += shift;
6866:   }
6867:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6868:   if (globalSize) {
6869:     PetscLayout layout;
6870:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6871:     PetscLayoutGetSize(layout, globalSize);
6872:     PetscLayoutDestroy(&layout);
6873:   }
6874:   PetscSectionDestroy(&section);
6875:   PetscSectionDestroy(&globalSection);
6876:   return(0);
6877: }

6879: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6880: {
6881:   PetscInt       cellHeight, cStart, cEnd, cMax;

6885:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6886:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6887:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6888:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6889:   DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6890:   return(0);
6891: }

6893: /*@
6894:   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process

6896:   Input Parameter:
6897: . dm   - The DMPlex object

6899:   Output Parameter:
6900: . globalCellNumbers - Global cell numbers for all cells on this process

6902:   Level: developer

6904: .seealso DMPlexGetVertexNumbering()
6905: @*/
6906: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6907: {
6908:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6913:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6914:   *globalCellNumbers = mesh->globalCellNumbers;
6915:   return(0);
6916: }

6918: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6919: {
6920:   PetscInt       vStart, vEnd, vMax;

6925:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6926:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6927:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6928:   DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6929:   return(0);
6930: }

6932: /*@
6933:   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process

6935:   Input Parameter:
6936: . dm   - The DMPlex object

6938:   Output Parameter:
6939: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6941:   Level: developer

6943: .seealso DMPlexGetCellNumbering()
6944: @*/
6945: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6946: {
6947:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6952:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6953:   *globalVertexNumbers = mesh->globalVertexNumbers;
6954:   return(0);
6955: }

6957: /*@
6958:   DMPlexCreatePointNumbering - Create a global numbering for all points on this process

6960:   Input Parameter:
6961: . dm   - The DMPlex object

6963:   Output Parameter:
6964: . globalPointNumbers - Global numbers for all points on this process

6966:   Level: developer

6968: .seealso DMPlexGetCellNumbering()
6969: @*/
6970: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6971: {
6972:   IS             nums[4];
6973:   PetscInt       depths[4], gdepths[4], starts[4];
6974:   PetscInt       depth, d, shift = 0;

6979:   DMPlexGetDepth(dm, &depth);
6980:   /* For unstratified meshes use dim instead of depth */
6981:   if (depth < 0) {DMGetDimension(dm, &depth);}
6982:   for (d = 0; d <= depth; ++d) {
6983:     PetscInt end;

6985:     depths[d] = depth-d;
6986:     DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6987:     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6988:   }
6989:   PetscSortIntWithArray(depth+1, starts, depths);
6990:   MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6991:   for (d = 0; d <= depth; ++d) {
6992:     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6993:   }
6994:   for (d = 0; d <= depth; ++d) {
6995:     PetscInt pStart, pEnd, gsize;

6997:     DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6998:     DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6999:     shift += gsize;
7000:   }
7001:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
7002:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
7003:   return(0);
7004: }


7007: /*@
7008:   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner

7010:   Input Parameter:
7011: . dm - The DMPlex object

7013:   Output Parameter:
7014: . ranks - The rank field

7016:   Options Database Keys:
7017: . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer

7019:   Level: intermediate

7021: .seealso: DMView()
7022: @*/
7023: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
7024: {
7025:   DM             rdm;
7026:   PetscFE        fe;
7027:   PetscScalar   *r;
7028:   PetscMPIInt    rank;
7029:   PetscInt       dim, cStart, cEnd, c;

7035:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
7036:   DMClone(dm, &rdm);
7037:   DMGetDimension(rdm, &dim);
7038:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
7039:   PetscObjectSetName((PetscObject) fe, "rank");
7040:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
7041:   PetscFEDestroy(&fe);
7042:   DMCreateDS(rdm);
7043:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
7044:   DMCreateGlobalVector(rdm, ranks);
7045:   PetscObjectSetName((PetscObject) *ranks, "partition");
7046:   VecGetArray(*ranks, &r);
7047:   for (c = cStart; c < cEnd; ++c) {
7048:     PetscScalar *lr;

7050:     DMPlexPointGlobalRef(rdm, c, r, &lr);
7051:     *lr = rank;
7052:   }
7053:   VecRestoreArray(*ranks, &r);
7054:   DMDestroy(&rdm);
7055:   return(0);
7056: }

7058: /*@
7059:   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell

7061:   Input Parameters:
7062: + dm    - The DMPlex
7063: - label - The DMLabel

7065:   Output Parameter:
7066: . val - The label value field

7068:   Options Database Keys:
7069: . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer

7071:   Level: intermediate

7073: .seealso: DMView()
7074: @*/
7075: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
7076: {
7077:   DM             rdm;
7078:   PetscFE        fe;
7079:   PetscScalar   *v;
7080:   PetscInt       dim, cStart, cEnd, c;

7087:   DMClone(dm, &rdm);
7088:   DMGetDimension(rdm, &dim);
7089:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
7090:   PetscObjectSetName((PetscObject) fe, "label_value");
7091:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
7092:   PetscFEDestroy(&fe);
7093:   DMCreateDS(rdm);
7094:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
7095:   DMCreateGlobalVector(rdm, val);
7096:   PetscObjectSetName((PetscObject) *val, "label_value");
7097:   VecGetArray(*val, &v);
7098:   for (c = cStart; c < cEnd; ++c) {
7099:     PetscScalar *lv;
7100:     PetscInt     cval;

7102:     DMPlexPointGlobalRef(rdm, c, v, &lv);
7103:     DMLabelGetValue(label, c, &cval);
7104:     *lv = cval;
7105:   }
7106:   VecRestoreArray(*val, &v);
7107:   DMDestroy(&rdm);
7108:   return(0);
7109: }

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

7114:   Input Parameter:
7115: . dm - The DMPlex object

7117:   Notes:
7118:   This is a useful diagnostic when creating meshes programmatically.

7120:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7122:   Level: developer

7124: .seealso: DMCreate(), DMSetFromOptions()
7125: @*/
7126: PetscErrorCode DMPlexCheckSymmetry(DM dm)
7127: {
7128:   PetscSection    coneSection, supportSection;
7129:   const PetscInt *cone, *support;
7130:   PetscInt        coneSize, c, supportSize, s;
7131:   PetscInt        pStart, pEnd, p, pp, csize, ssize;
7132:   PetscBool       storagecheck = PETSC_TRUE;
7133:   PetscErrorCode  ierr;

7137:   DMPlexGetConeSection(dm, &coneSection);
7138:   DMPlexGetSupportSection(dm, &supportSection);
7139:   /* Check that point p is found in the support of its cone points, and vice versa */
7140:   DMPlexGetChart(dm, &pStart, &pEnd);
7141:   for (p = pStart; p < pEnd; ++p) {
7142:     DMPlexGetConeSize(dm, p, &coneSize);
7143:     DMPlexGetCone(dm, p, &cone);
7144:     for (c = 0; c < coneSize; ++c) {
7145:       PetscBool dup = PETSC_FALSE;
7146:       PetscInt  d;
7147:       for (d = c-1; d >= 0; --d) {
7148:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
7149:       }
7150:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
7151:       DMPlexGetSupport(dm, cone[c], &support);
7152:       for (s = 0; s < supportSize; ++s) {
7153:         if (support[s] == p) break;
7154:       }
7155:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
7156:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
7157:         for (s = 0; s < coneSize; ++s) {
7158:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
7159:         }
7160:         PetscPrintf(PETSC_COMM_SELF, "\n");
7161:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
7162:         for (s = 0; s < supportSize; ++s) {
7163:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
7164:         }
7165:         PetscPrintf(PETSC_COMM_SELF, "\n");
7166:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
7167:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
7168:       }
7169:     }
7170:     DMPlexGetTreeParent(dm, p, &pp, NULL);
7171:     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
7172:     DMPlexGetSupportSize(dm, p, &supportSize);
7173:     DMPlexGetSupport(dm, p, &support);
7174:     for (s = 0; s < supportSize; ++s) {
7175:       DMPlexGetConeSize(dm, support[s], &coneSize);
7176:       DMPlexGetCone(dm, support[s], &cone);
7177:       for (c = 0; c < coneSize; ++c) {
7178:         DMPlexGetTreeParent(dm, cone[c], &pp, NULL);
7179:         if (cone[c] != pp) { c = 0; break; }
7180:         if (cone[c] == p) break;
7181:       }
7182:       if (c >= coneSize) {
7183:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
7184:         for (c = 0; c < supportSize; ++c) {
7185:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
7186:         }
7187:         PetscPrintf(PETSC_COMM_SELF, "\n");
7188:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
7189:         for (c = 0; c < coneSize; ++c) {
7190:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
7191:         }
7192:         PetscPrintf(PETSC_COMM_SELF, "\n");
7193:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
7194:       }
7195:     }
7196:   }
7197:   if (storagecheck) {
7198:     PetscSectionGetStorageSize(coneSection, &csize);
7199:     PetscSectionGetStorageSize(supportSection, &ssize);
7200:     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
7201:   }
7202:   return(0);
7203: }

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

7208:   Input Parameters:
7209: + dm - The DMPlex object
7210: - cellHeight - Normally 0

7212:   Notes:
7213:   This is a useful diagnostic when creating meshes programmatically.
7214:   Currently applicable only to homogeneous simplex or tensor meshes.

7216:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7218:   Level: developer

7220: .seealso: DMCreate(), DMSetFromOptions()
7221: @*/
7222: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
7223: {
7224:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
7225:   PetscBool      isSimplex = PETSC_FALSE;

7230:   DMGetDimension(dm, &dim);
7231:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
7232:   if (cStart < cEnd) {
7233:     DMPlexGetConeSize(dm, cStart, &c);
7234:     isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE;
7235:   }
7236:   switch (dim) {
7237:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
7238:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
7239:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
7240:   default:
7241:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
7242:   }
7243:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7244:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
7245:   cMax = cMax >= 0 ? cMax : cEnd;
7246:   for (c = cStart; c < cMax; ++c) {
7247:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

7249:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7250:     for (cl = 0; cl < closureSize*2; cl += 2) {
7251:       const PetscInt p = closure[cl];
7252:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
7253:     }
7254:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7255:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
7256:   }
7257:   for (c = cMax; c < cEnd; ++c) {
7258:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

7260:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7261:     for (cl = 0; cl < closureSize*2; cl += 2) {
7262:       const PetscInt p = closure[cl];
7263:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
7264:     }
7265:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7266:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
7267:   }
7268:   return(0);
7269: }

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

7274:   Not Collective

7276:   Input Parameters:
7277: + dm - The DMPlex object
7278: - cellHeight - Normally 0

7280:   Notes:
7281:   This is a useful diagnostic when creating meshes programmatically.
7282:   This routine is only relevant for meshes that are fully interpolated across all ranks.
7283:   It will error out if a partially interpolated mesh is given on some rank.
7284:   It will do nothing for locally uninterpolated mesh (as there is nothing to check).

7286:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7288:   Level: developer

7290: .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions()
7291: @*/
7292: PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
7293: {
7294:   PetscInt       pMax[4];
7295:   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
7297:   DMPlexInterpolatedFlag interpEnum;

7301:   DMPlexIsInterpolated(dm, &interpEnum);
7302:   if (interpEnum == DMPLEX_INTERPOLATED_NONE) return(0);
7303:   if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) {
7304:     PetscMPIInt        rank;
7305:     MPI_Comm        comm;

7307:     PetscObjectGetComm((PetscObject) dm, &comm);
7308:     MPI_Comm_rank(comm, &rank);
7309:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank);
7310:   }

7312:   DMGetDimension(dm, &dim);
7313:   DMPlexGetDepth(dm, &depth);
7314:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7315:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
7316:   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
7317:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
7318:     for (c = cStart; c < cEnd; ++c) {
7319:       const PetscInt *cone, *ornt, *faces;
7320:       DMPolytopeType  ct;
7321:       PetscInt        numFaces, faceSize, coneSize,f;
7322:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

7324:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
7325:       DMPlexGetCellType(dm, c, &ct);
7326:       DMPlexGetConeSize(dm, c, &coneSize);
7327:       DMPlexGetCone(dm, c, &cone);
7328:       DMPlexGetConeOrientation(dm, c, &ornt);
7329:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7330:       for (cl = 0; cl < closureSize*2; cl += 2) {
7331:         const PetscInt p = closure[cl];
7332:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
7333:       }
7334:       DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceSize, &faces);
7335:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
7336:       for (f = 0; f < numFaces; ++f) {
7337:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

7339:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
7340:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
7341:           const PetscInt p = fclosure[cl];
7342:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
7343:         }
7344:         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);
7345:         for (v = 0; v < fnumCorners; ++v) {
7346:           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]);
7347:         }
7348:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
7349:       }
7350:       DMPlexRestoreFaces_Internal(dm, ct, &numFaces, &faceSize, &faces);
7351:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
7352:     }
7353:   }
7354:   return(0);
7355: }

7357: /*@
7358:   DMPlexCheckGeometry - Check the geometry of mesh cells

7360:   Input Parameter:
7361: . dm - The DMPlex object

7363:   Notes:
7364:   This is a useful diagnostic when creating meshes programmatically.

7366:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7368:   Level: developer

7370: .seealso: DMCreate(), DMSetFromOptions()
7371: @*/
7372: PetscErrorCode DMPlexCheckGeometry(DM dm)
7373: {
7374:   PetscReal      detJ, J[9], refVol = 1.0;
7375:   PetscReal      vol;
7376:   PetscInt       dim, depth, d, cStart, cEnd, c, cMax;

7380:   DMGetDimension(dm, &dim);
7381:   DMPlexGetDepth(dm, &depth);
7382:   for (d = 0; d < dim; ++d) refVol *= 2.0;
7383:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7384:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
7385:   cMax = cMax < 0 ? cEnd : cMax;
7386:   for (c = cStart; c < cMax; ++c) {
7387:     DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
7388:     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
7389:     PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
7390:     if (depth > 1) {
7391:       DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
7392:       if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
7393:       PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
7394:     }
7395:   }
7396:   return(0);
7397: }

7399: /*@
7400:   DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.

7402:   Input Parameters:
7403: . dm - The DMPlex object

7405:   Notes:
7406:   This is mainly intended for debugging/testing purposes.
7407:   It currently checks only meshes with no partition overlapping.

7409:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7411:   Level: developer

7413: .seealso: DMGetPointSF(), DMSetFromOptions()
7414: @*/
7415: PetscErrorCode DMPlexCheckPointSF(DM dm)
7416: {
7417:   PetscSF         pointSF;
7418:   PetscInt        cellHeight, cStart, cEnd, l, nleaves, nroots, overlap;
7419:   const PetscInt *locals, *rootdegree;
7420:   PetscBool       distributed;
7421:   PetscErrorCode  ierr;

7425:   DMGetPointSF(dm, &pointSF);
7426:   DMPlexIsDistributed(dm, &distributed);
7427:   if (!distributed) return(0);
7428:   DMPlexGetOverlap(dm, &overlap);
7429:   if (overlap) {
7430:     PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");
7431:     return(0);
7432:   }
7433:   if (!pointSF) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached");
7434:   PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);
7435:   if (nroots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
7436:   PetscSFComputeDegreeBegin(pointSF, &rootdegree);
7437:   PetscSFComputeDegreeEnd(pointSF, &rootdegree);

7439:   /* 1) check there are no faces in 2D, cells in 3D, in interface */
7440:   DMPlexGetVTKCellHeight(dm, &cellHeight);
7441:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
7442:   for (l = 0; l < nleaves; ++l) {
7443:     const PetscInt point = locals[l];

7445:     if (point >= cStart && point < cEnd) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point);
7446:   }

7448:   /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
7449:   for (l = 0; l < nleaves; ++l) {
7450:     const PetscInt  point = locals[l];
7451:     const PetscInt *cone;
7452:     PetscInt        coneSize, c, idx;

7454:     DMPlexGetConeSize(dm, point, &coneSize);
7455:     DMPlexGetCone(dm, point, &cone);
7456:     for (c = 0; c < coneSize; ++c) {
7457:       if (!rootdegree[cone[c]]) {
7458:         PetscFindInt(cone[c], nleaves, locals, &idx);
7459:         if (idx < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]);
7460:       }
7461:     }
7462:   }
7463:   return(0);
7464: }

7466: typedef struct cell_stats
7467: {
7468:   PetscReal min, max, sum, squaresum;
7469:   PetscInt  count;
7470: } cell_stats_t;

7472: static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
7473: {
7474:   PetscInt i, N = *len;

7476:   for (i = 0; i < N; i++) {
7477:     cell_stats_t *A = (cell_stats_t *) a;
7478:     cell_stats_t *B = (cell_stats_t *) b;

7480:     B->min = PetscMin(A->min,B->min);
7481:     B->max = PetscMax(A->max,B->max);
7482:     B->sum += A->sum;
7483:     B->squaresum += A->squaresum;
7484:     B->count += A->count;
7485:   }
7486: }

7488: /*@
7489:   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.

7491:   Collective on dm

7493:   Input Parameters:
7494: + dm        - The DMPlex object
7495: . output    - If true, statistics will be displayed on stdout
7496: - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output

7498:   Notes:
7499:   This is mainly intended for debugging/testing purposes.

7501:   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().

7503:   Level: developer

7505: .seealso: DMSetFromOptions()
7506: @*/
7507: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
7508: {
7509:   DM             dmCoarse;
7510:   cell_stats_t   stats, globalStats;
7511:   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
7512:   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
7513:   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
7514:   PetscInt       cdim, cStart, cEnd, cMax, c, eStart, eEnd, count = 0;
7515:   PetscMPIInt    rank,size;

7520:   stats.min   = PETSC_MAX_REAL;
7521:   stats.max   = PETSC_MIN_REAL;
7522:   stats.sum   = stats.squaresum = 0.;
7523:   stats.count = 0;

7525:   MPI_Comm_size(comm, &size);
7526:   MPI_Comm_rank(comm, &rank);
7527:   DMGetCoordinateDim(dm,&cdim);
7528:   PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);
7529:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
7530:   DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);
7531:   DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
7532:   cMax = cMax < 0 ? cEnd : cMax;
7533:   for (c = cStart; c < cMax; c++) {
7534:     PetscInt  i;
7535:     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;

7537:     DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
7538:     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
7539:     for (i = 0; i < PetscSqr(cdim); ++i) {
7540:       frobJ    += J[i] * J[i];
7541:       frobInvJ += invJ[i] * invJ[i];
7542:     }
7543:     cond2 = frobJ * frobInvJ;
7544:     cond  = PetscSqrtReal(cond2);

7546:     stats.min        = PetscMin(stats.min,cond);
7547:     stats.max        = PetscMax(stats.max,cond);
7548:     stats.sum       += cond;
7549:     stats.squaresum += cond2;
7550:     stats.count++;
7551:     if (output && cond > limit) {
7552:       PetscSection coordSection;
7553:       Vec          coordsLocal;
7554:       PetscScalar *coords = NULL;
7555:       PetscInt     Nv, d, clSize, cl, *closure = NULL;

7557:       DMGetCoordinatesLocal(dm, &coordsLocal);
7558:       DMGetCoordinateSection(dm, &coordSection);
7559:       DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);
7560:       PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);
7561:       for (i = 0; i < Nv/cdim; ++i) {
7562:         PetscSynchronizedPrintf(comm, "  Vertex %D: (", i);
7563:         for (d = 0; d < cdim; ++d) {
7564:           if (d > 0) {PetscSynchronizedPrintf(comm, ", ");}
7565:           PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));
7566:         }
7567:         PetscSynchronizedPrintf(comm, ")\n");
7568:       }
7569:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
7570:       for (cl = 0; cl < clSize*2; cl += 2) {
7571:         const PetscInt edge = closure[cl];

7573:         if ((edge >= eStart) && (edge < eEnd)) {
7574:           PetscReal len;

7576:           DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);
7577:           PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len);
7578:         }
7579:       }
7580:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);
7581:       DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);
7582:     }
7583:   }
7584:   if (output) {PetscSynchronizedFlush(comm, NULL);}

7586:   if (size > 1) {
7587:     PetscMPIInt   blockLengths[2] = {4,1};
7588:     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
7589:     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
7590:     MPI_Op        statReduce;

7592:     MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
7593:     MPI_Type_commit(&statType);
7594:     MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
7595:     MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
7596:     MPI_Op_free(&statReduce);
7597:     MPI_Type_free(&statType);
7598:   } else {
7599:     PetscArraycpy(&globalStats,&stats,1);
7600:   }
7601:   if (!rank) {
7602:     count = globalStats.count;
7603:     min   = globalStats.min;
7604:     max   = globalStats.max;
7605:     mean  = globalStats.sum / globalStats.count;
7606:     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
7607:   }

7609:   if (output) {
7610:     PetscPrintf(comm,"Mesh with %D cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double) min, (double) max, (double) mean, (double) stdev);
7611:   }
7612:   PetscFree2(J,invJ);

7614:   DMGetCoarseDM(dm,&dmCoarse);
7615:   if (dmCoarse) {
7616:     PetscBool isplex;

7618:     PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
7619:     if (isplex) {
7620:       DMPlexCheckCellShape(dmCoarse,output,condLimit);
7621:     }
7622:   }
7623:   return(0);
7624: }

7626: /* Pointwise interpolation
7627:      Just code FEM for now
7628:      u^f = I u^c
7629:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
7630:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
7631:      I_{ij} = psi^f_i phi^c_j
7632: */
7633: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
7634: {
7635:   PetscSection   gsc, gsf;
7636:   PetscInt       m, n;
7637:   void          *ctx;
7638:   DM             cdm;
7639:   PetscBool      regular, ismatis;

7643:   DMGetGlobalSection(dmFine, &gsf);
7644:   PetscSectionGetConstrainedStorageSize(gsf, &m);
7645:   DMGetGlobalSection(dmCoarse, &gsc);
7646:   PetscSectionGetConstrainedStorageSize(gsc, &n);

7648:   PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
7649:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
7650:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7651:   MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
7652:   DMGetApplicationContext(dmFine, &ctx);

7654:   DMGetCoarseDM(dmFine, &cdm);
7655:   DMPlexGetRegularRefinement(dmFine, &regular);
7656:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
7657:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
7658:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
7659:   if (scaling) {
7660:     /* Use naive scaling */
7661:     DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
7662:   }
7663:   return(0);
7664: }

7666: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
7667: {
7669:   VecScatter     ctx;

7672:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
7673:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
7674:   VecScatterDestroy(&ctx);
7675:   return(0);
7676: }

7678: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
7679: {
7680:   PetscSection   gsc, gsf;
7681:   PetscInt       m, n;
7682:   void          *ctx;
7683:   DM             cdm;
7684:   PetscBool      regular;

7688:   DMGetGlobalSection(dmFine, &gsf);
7689:   PetscSectionGetConstrainedStorageSize(gsf, &m);
7690:   DMGetGlobalSection(dmCoarse, &gsc);
7691:   PetscSectionGetConstrainedStorageSize(gsc, &n);

7693:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
7694:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7695:   MatSetType(*mass, dmCoarse->mattype);
7696:   DMGetApplicationContext(dmFine, &ctx);

7698:   DMGetCoarseDM(dmFine, &cdm);
7699:   DMPlexGetRegularRefinement(dmFine, &regular);
7700:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
7701:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
7702:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
7703:   return(0);
7704: }

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

7709:   Input Parameter:
7710: . dm - The DMPlex object

7712:   Output Parameter:
7713: . regular - The flag

7715:   Level: intermediate

7717: .seealso: DMPlexSetRegularRefinement()
7718: @*/
7719: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7720: {
7724:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
7725:   return(0);
7726: }

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

7731:   Input Parameters:
7732: + dm - The DMPlex object
7733: - regular - The flag

7735:   Level: intermediate

7737: .seealso: DMPlexGetRegularRefinement()
7738: @*/
7739: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7740: {
7743:   ((DM_Plex *) dm->data)->regularRefinement = regular;
7744:   return(0);
7745: }

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

7752:   not collective

7754:   Input Parameters:
7755: . dm - The DMPlex object

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


7762:   Level: intermediate

7764: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7765: @*/
7766: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7767: {
7768:   DM_Plex *plex = (DM_Plex *)dm->data;

7773:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7774:   if (anchorSection) *anchorSection = plex->anchorSection;
7775:   if (anchorIS) *anchorIS = plex->anchorIS;
7776:   return(0);
7777: }

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

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

7787:   collective on dm

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

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

7796:   Level: intermediate

7798: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7799: @*/
7800: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7801: {
7802:   DM_Plex        *plex = (DM_Plex *)dm->data;
7803:   PetscMPIInt    result;

7808:   if (anchorSection) {
7810:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7811:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7812:   }
7813:   if (anchorIS) {
7815:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7816:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7817:   }

7819:   PetscObjectReference((PetscObject)anchorSection);
7820:   PetscSectionDestroy(&plex->anchorSection);
7821:   plex->anchorSection = anchorSection;

7823:   PetscObjectReference((PetscObject)anchorIS);
7824:   ISDestroy(&plex->anchorIS);
7825:   plex->anchorIS = anchorIS;

7827: #if defined(PETSC_USE_DEBUG)
7828:   if (anchorIS && anchorSection) {
7829:     PetscInt size, a, pStart, pEnd;
7830:     const PetscInt *anchors;

7832:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7833:     ISGetLocalSize(anchorIS,&size);
7834:     ISGetIndices(anchorIS,&anchors);
7835:     for (a = 0; a < size; a++) {
7836:       PetscInt p;

7838:       p = anchors[a];
7839:       if (p >= pStart && p < pEnd) {
7840:         PetscInt dof;

7842:         PetscSectionGetDof(anchorSection,p,&dof);
7843:         if (dof) {
7844:           PetscErrorCode ierr2;

7846:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7847:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7848:         }
7849:       }
7850:     }
7851:     ISRestoreIndices(anchorIS,&anchors);
7852:   }
7853: #endif
7854:   /* reset the generic constraints */
7855:   DMSetDefaultConstraints(dm,NULL,NULL);
7856:   return(0);
7857: }

7859: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7860: {
7861:   PetscSection anchorSection;
7862:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

7867:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7868:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
7869:   PetscSectionGetNumFields(section,&numFields);
7870:   if (numFields) {
7871:     PetscInt f;
7872:     PetscSectionSetNumFields(*cSec,numFields);

7874:     for (f = 0; f < numFields; f++) {
7875:       PetscInt numComp;

7877:       PetscSectionGetFieldComponents(section,f,&numComp);
7878:       PetscSectionSetFieldComponents(*cSec,f,numComp);
7879:     }
7880:   }
7881:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7882:   PetscSectionGetChart(section,&sStart,&sEnd);
7883:   pStart = PetscMax(pStart,sStart);
7884:   pEnd   = PetscMin(pEnd,sEnd);
7885:   pEnd   = PetscMax(pStart,pEnd);
7886:   PetscSectionSetChart(*cSec,pStart,pEnd);
7887:   for (p = pStart; p < pEnd; p++) {
7888:     PetscSectionGetDof(anchorSection,p,&dof);
7889:     if (dof) {
7890:       PetscSectionGetDof(section,p,&dof);
7891:       PetscSectionSetDof(*cSec,p,dof);
7892:       for (f = 0; f < numFields; f++) {
7893:         PetscSectionGetFieldDof(section,p,f,&dof);
7894:         PetscSectionSetFieldDof(*cSec,p,f,dof);
7895:       }
7896:     }
7897:   }
7898:   PetscSectionSetUp(*cSec);
7899:   return(0);
7900: }

7902: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7903: {
7904:   PetscSection aSec;
7905:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7906:   const PetscInt *anchors;
7907:   PetscInt numFields, f;
7908:   IS aIS;

7913:   PetscSectionGetStorageSize(cSec, &m);
7914:   PetscSectionGetStorageSize(section, &n);
7915:   MatCreate(PETSC_COMM_SELF,cMat);
7916:   MatSetSizes(*cMat,m,n,m,n);
7917:   MatSetType(*cMat,MATSEQAIJ);
7918:   DMPlexGetAnchors(dm,&aSec,&aIS);
7919:   ISGetIndices(aIS,&anchors);
7920:   /* cSec will be a subset of aSec and section */
7921:   PetscSectionGetChart(cSec,&pStart,&pEnd);
7922:   PetscMalloc1(m+1,&i);
7923:   i[0] = 0;
7924:   PetscSectionGetNumFields(section,&numFields);
7925:   for (p = pStart; p < pEnd; p++) {
7926:     PetscInt rDof, rOff, r;

7928:     PetscSectionGetDof(aSec,p,&rDof);
7929:     if (!rDof) continue;
7930:     PetscSectionGetOffset(aSec,p,&rOff);
7931:     if (numFields) {
7932:       for (f = 0; f < numFields; f++) {
7933:         annz = 0;
7934:         for (r = 0; r < rDof; r++) {
7935:           a = anchors[rOff + r];
7936:           PetscSectionGetFieldDof(section,a,f,&aDof);
7937:           annz += aDof;
7938:         }
7939:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7940:         PetscSectionGetFieldOffset(cSec,p,f,&off);
7941:         for (q = 0; q < dof; q++) {
7942:           i[off + q + 1] = i[off + q] + annz;
7943:         }
7944:       }
7945:     }
7946:     else {
7947:       annz = 0;
7948:       for (q = 0; q < dof; q++) {
7949:         a = anchors[off + q];
7950:         PetscSectionGetDof(section,a,&aDof);
7951:         annz += aDof;
7952:       }
7953:       PetscSectionGetDof(cSec,p,&dof);
7954:       PetscSectionGetOffset(cSec,p,&off);
7955:       for (q = 0; q < dof; q++) {
7956:         i[off + q + 1] = i[off + q] + annz;
7957:       }
7958:     }
7959:   }
7960:   nnz = i[m];
7961:   PetscMalloc1(nnz,&j);
7962:   offset = 0;
7963:   for (p = pStart; p < pEnd; p++) {
7964:     if (numFields) {
7965:       for (f = 0; f < numFields; f++) {
7966:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7967:         for (q = 0; q < dof; q++) {
7968:           PetscInt rDof, rOff, r;
7969:           PetscSectionGetDof(aSec,p,&rDof);
7970:           PetscSectionGetOffset(aSec,p,&rOff);
7971:           for (r = 0; r < rDof; r++) {
7972:             PetscInt s;

7974:             a = anchors[rOff + r];
7975:             PetscSectionGetFieldDof(section,a,f,&aDof);
7976:             PetscSectionGetFieldOffset(section,a,f,&aOff);
7977:             for (s = 0; s < aDof; s++) {
7978:               j[offset++] = aOff + s;
7979:             }
7980:           }
7981:         }
7982:       }
7983:     }
7984:     else {
7985:       PetscSectionGetDof(cSec,p,&dof);
7986:       for (q = 0; q < dof; q++) {
7987:         PetscInt rDof, rOff, r;
7988:         PetscSectionGetDof(aSec,p,&rDof);
7989:         PetscSectionGetOffset(aSec,p,&rOff);
7990:         for (r = 0; r < rDof; r++) {
7991:           PetscInt s;

7993:           a = anchors[rOff + r];
7994:           PetscSectionGetDof(section,a,&aDof);
7995:           PetscSectionGetOffset(section,a,&aOff);
7996:           for (s = 0; s < aDof; s++) {
7997:             j[offset++] = aOff + s;
7998:           }
7999:         }
8000:       }
8001:     }
8002:   }
8003:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
8004:   PetscFree(i);
8005:   PetscFree(j);
8006:   ISRestoreIndices(aIS,&anchors);
8007:   return(0);
8008: }

8010: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
8011: {
8012:   DM_Plex        *plex = (DM_Plex *)dm->data;
8013:   PetscSection   anchorSection, section, cSec;
8014:   Mat            cMat;

8019:   DMPlexGetAnchors(dm,&anchorSection,NULL);
8020:   if (anchorSection) {
8021:     PetscInt Nf;

8023:     DMGetLocalSection(dm,&section);
8024:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
8025:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
8026:     DMGetNumFields(dm,&Nf);
8027:     if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
8028:     DMSetDefaultConstraints(dm,cSec,cMat);
8029:     PetscSectionDestroy(&cSec);
8030:     MatDestroy(&cMat);
8031:   }
8032:   return(0);
8033: }

8035: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
8036: {
8037:   IS             subis;
8038:   PetscSection   section, subsection;

8042:   DMGetLocalSection(dm, &section);
8043:   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
8044:   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
8045:   /* Create subdomain */
8046:   DMPlexFilter(dm, label, value, subdm);
8047:   /* Create submodel */
8048:   DMPlexCreateSubpointIS(*subdm, &subis);
8049:   PetscSectionCreateSubmeshSection(section, subis, &subsection);
8050:   ISDestroy(&subis);
8051:   DMSetLocalSection(*subdm, subsection);
8052:   PetscSectionDestroy(&subsection);
8053:   DMCopyDisc(dm, *subdm);
8054:   /* Create map from submodel to global model */
8055:   if (is) {
8056:     PetscSection    sectionGlobal, subsectionGlobal;
8057:     IS              spIS;
8058:     const PetscInt *spmap;
8059:     PetscInt       *subIndices;
8060:     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
8061:     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];

8063:     DMPlexCreateSubpointIS(*subdm, &spIS);
8064:     ISGetIndices(spIS, &spmap);
8065:     PetscSectionGetNumFields(section, &Nf);
8066:     DMGetGlobalSection(dm, &sectionGlobal);
8067:     DMGetGlobalSection(*subdm, &subsectionGlobal);
8068:     PetscSectionGetChart(subsection, &pStart, &pEnd);
8069:     for (p = pStart; p < pEnd; ++p) {
8070:       PetscInt gdof, pSubSize  = 0;

8072:       PetscSectionGetDof(sectionGlobal, p, &gdof);
8073:       if (gdof > 0) {
8074:         for (f = 0; f < Nf; ++f) {
8075:           PetscInt fdof, fcdof;

8077:           PetscSectionGetFieldDof(subsection, p, f, &fdof);
8078:           PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
8079:           pSubSize += fdof-fcdof;
8080:         }
8081:         subSize += pSubSize;
8082:         if (pSubSize) {
8083:           if (bs < 0) {
8084:             bs = pSubSize;
8085:           } else if (bs != pSubSize) {
8086:             /* Layout does not admit a pointwise block size */
8087:             bs = 1;
8088:           }
8089:         }
8090:       }
8091:     }
8092:     /* Must have same blocksize on all procs (some might have no points) */
8093:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
8094:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
8095:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
8096:     else                            {bs = bsMinMax[0];}
8097:     PetscMalloc1(subSize, &subIndices);
8098:     for (p = pStart; p < pEnd; ++p) {
8099:       PetscInt gdof, goff;

8101:       PetscSectionGetDof(subsectionGlobal, p, &gdof);
8102:       if (gdof > 0) {
8103:         const PetscInt point = spmap[p];

8105:         PetscSectionGetOffset(sectionGlobal, point, &goff);
8106:         for (f = 0; f < Nf; ++f) {
8107:           PetscInt fdof, fcdof, fc, f2, poff = 0;

8109:           /* Can get rid of this loop by storing field information in the global section */
8110:           for (f2 = 0; f2 < f; ++f2) {
8111:             PetscSectionGetFieldDof(section, p, f2, &fdof);
8112:             PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
8113:             poff += fdof-fcdof;
8114:           }
8115:           PetscSectionGetFieldDof(section, p, f, &fdof);
8116:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
8117:           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
8118:             subIndices[subOff] = goff+poff+fc;
8119:           }
8120:         }
8121:       }
8122:     }
8123:     ISRestoreIndices(spIS, &spmap);
8124:     ISDestroy(&spIS);
8125:     ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
8126:     if (bs > 1) {
8127:       /* We need to check that the block size does not come from non-contiguous fields */
8128:       PetscInt i, j, set = 1;
8129:       for (i = 0; i < subSize; i += bs) {
8130:         for (j = 0; j < bs; ++j) {
8131:           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
8132:         }
8133:       }
8134:       if (set) {ISSetBlockSize(*is, bs);}
8135:     }
8136:     /* Attach nullspace */
8137:     for (f = 0; f < Nf; ++f) {
8138:       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
8139:       if ((*subdm)->nullspaceConstructors[f]) break;
8140:     }
8141:     if (f < Nf) {
8142:       MatNullSpace nullSpace;

8144:       (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
8145:       PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
8146:       MatNullSpaceDestroy(&nullSpace);
8147:     }
8148:   }
8149:   return(0);
8150: }

8152: /*@
8153:   DMPlexMonitorThroughput - Report the cell throughput of FE integration

8155:   Input Parameter:
8156: - dm - The DM

8158:   Level: developer

8160:   Options Database Keys:
8161: . -dm_plex_monitor_throughput - Activate the monitor

8163: .seealso: DMSetFromOptions(), DMPlexCreate()
8164: @*/
8165: PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
8166: {
8167:   PetscStageLog      stageLog;
8168:   PetscLogEvent      event;
8169:   PetscLogStage      stage;
8170:   PetscEventPerfInfo eventInfo;
8171:   PetscReal          cellRate, flopRate;
8172:   PetscInt           cStart, cEnd, Nf, N;
8173:   const char        *name;
8174:   PetscErrorCode     ierr;

8178: #if defined(PETSC_USE_LOG)
8179:   PetscObjectGetName((PetscObject) dm, &name);
8180:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
8181:   DMGetNumFields(dm, &Nf);
8182:   PetscLogGetStageLog(&stageLog);
8183:   PetscStageLogGetCurrent(stageLog, &stage);
8184:   PetscLogEventGetId("DMPlexResidualFE", &event);
8185:   PetscLogEventGetPerfInfo(stage, event, &eventInfo);
8186:   N        = (cEnd - cStart)*Nf*eventInfo.count;
8187:   flopRate = eventInfo.flops/eventInfo.time;
8188:   cellRate = N/eventInfo.time;
8189:   PetscPrintf(PetscObjectComm((PetscObject) dm), "DM (%s) FE Residual Integration: %D integrals %D reps\n  Cell rate: %.2g/s flop rate: %.2g MF/s\n", name ? name : "unknown", N, eventInfo.count, (double) cellRate, (double) flopRate/1.e6);
8190: #else
8191:   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
8192: #endif
8193:   return(0);
8194: }