Actual source code: plex.c

petsc-master 2019-05-18
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:   PetscInt         dim, cMax, fMax, cStart, cEnd, coneSize;
 36:   CellRefiner      cellRefiner;
 37:   PetscBool        lop, allnoop, localized;
 38:   PetscErrorCode   ierr;

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

102: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
103: {
104:   PetscInt       dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior;
105:   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];

109:   *ft  = PETSC_VTK_POINT_FIELD;
110:   DMGetDimension(dm, &dim);
111:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
112:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
113:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
114:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
115:   PetscSectionGetChart(section, &pStart, &pEnd);
116:   if (field >= 0) {
117:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);}
118:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);}
119:   } else {
120:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vcdof[0]);}
121:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &vcdof[1]);}
122:   }
123:   MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
124:   if (globalvcdof[0]) {
125:     *sStart = vStart;
126:     *sEnd   = vEnd;
127:     if (globalvcdof[0] == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
128:     else                       *ft = PETSC_VTK_POINT_FIELD;
129:   } else if (globalvcdof[1]) {
130:     *sStart = cStart;
131:     *sEnd   = cEnd;
132:     if (globalvcdof[1] == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
133:     else                       *ft = PETSC_VTK_CELL_FIELD;
134:   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
135:   return(0);
136: }

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

156:   PetscViewerDrawGetDraw(viewer, 0, &draw);
157:   PetscDrawIsNull(draw, &isnull);
158:   if (isnull) return(0);

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

172:   PetscObjectGetName((PetscObject) v, &name);
173:   DMGetOutputSequenceNumber(dm, &step, &time);

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

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

192:     PetscSectionGetFieldComponents(s, f, &Nc);
193:     PetscSectionGetFieldName(s, f, &fname);

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

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

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

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

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

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

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

288:   VecGetDM(v, &dm);
289:   DMCreateLocalVector(dm, &locv); /* VTK viewer requires exclusive ownership of the vector */
290:   PetscObjectGetName((PetscObject) v, &name);
291:   PetscObjectSetName((PetscObject) locv, name);
292:   VecCopy(v, locv);
293:   DMGetSection(dm, &section);
294:   DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
295:   PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, PETSC_TRUE,(PetscObject) locv);
296:   return(0);
297: }

299: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
300: {
301:   DM             dm;
302:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

306:   VecGetDM(v, &dm);
307:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
308:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
309:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
310:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
311:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
312:   if (isvtk || ishdf5 || isdraw || isglvis) {
313:     PetscInt    i,numFields;
314:     PetscObject fe;
315:     PetscBool   fem = PETSC_FALSE;
316:     Vec         locv = v;
317:     const char  *name;
318:     PetscInt    step;
319:     PetscReal   time;

321:     DMGetNumFields(dm, &numFields);
322:     for (i=0; i<numFields; i++) {
323:       DMGetField(dm, i, NULL, &fe);
324:       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
325:     }
326:     if (fem) {
327:       DMGetLocalVector(dm, &locv);
328:       PetscObjectGetName((PetscObject) v, &name);
329:       PetscObjectSetName((PetscObject) locv, name);
330:       VecCopy(v, locv);
331:       DMGetOutputSequenceNumber(dm, NULL, &time);
332:       DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
333:     }
334:     if (isvtk) {
335:       VecView_Plex_Local_VTK(locv, viewer);
336:     } else if (ishdf5) {
337: #if defined(PETSC_HAVE_HDF5)
338:       VecView_Plex_Local_HDF5_Internal(locv, viewer);
339: #else
340:       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
341: #endif
342:     } else if (isdraw) {
343:       VecView_Plex_Local_Draw(locv, viewer);
344:     } else if (isglvis) {
345:       DMGetOutputSequenceNumber(dm, &step, NULL);
346:       PetscViewerGLVisSetSnapId(viewer, step);
347:       VecView_GLVis(locv, viewer);
348:     }
349:     if (fem) {DMRestoreLocalVector(dm, &locv);}
350:   } else {
351:     PetscBool isseq;

353:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
354:     if (isseq) {VecView_Seq(v, viewer);}
355:     else       {VecView_MPI(v, viewer);}
356:   }
357:   return(0);
358: }

360: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
361: {
362:   DM             dm;
363:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

367:   VecGetDM(v, &dm);
368:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
369:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
370:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
371:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
372:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
373:   if (isvtk || isdraw || isglvis) {
374:     Vec         locv;
375:     const char *name;

377:     DMGetLocalVector(dm, &locv);
378:     PetscObjectGetName((PetscObject) v, &name);
379:     PetscObjectSetName((PetscObject) locv, name);
380:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
381:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
382:     VecView_Plex_Local(locv, viewer);
383:     DMRestoreLocalVector(dm, &locv);
384:   } else if (ishdf5) {
385: #if defined(PETSC_HAVE_HDF5)
386:     VecView_Plex_HDF5_Internal(v, viewer);
387: #else
388:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
389: #endif
390:   } else {
391:     PetscBool isseq;

393:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
394:     if (isseq) {VecView_Seq(v, viewer);}
395:     else       {VecView_MPI(v, viewer);}
396:   }
397:   return(0);
398: }

400: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
401: {
402:   DM                dm;
403:   MPI_Comm          comm;
404:   PetscViewerFormat format;
405:   Vec               v;
406:   PetscBool         isvtk, ishdf5;
407:   PetscErrorCode    ierr;

410:   VecGetDM(originalv, &dm);
411:   PetscObjectGetComm((PetscObject) originalv, &comm);
412:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
413:   PetscViewerGetFormat(viewer, &format);
414:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
415:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
416:   if (format == PETSC_VIEWER_NATIVE) {
417:     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
418:     /* this need a better fix */
419:     if (dm->useNatural) {
420:       if (dm->sfNatural) {
421:         const char *vecname;
422:         PetscInt    n, nroots;

424:         VecGetLocalSize(originalv, &n);
425:         PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
426:         if (n == nroots) {
427:           DMGetGlobalVector(dm, &v);
428:           DMPlexGlobalToNaturalBegin(dm, originalv, v);
429:           DMPlexGlobalToNaturalEnd(dm, originalv, v);
430:           PetscObjectGetName((PetscObject) originalv, &vecname);
431:           PetscObjectSetName((PetscObject) v, vecname);
432:         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
433:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
434:     } else v = originalv;
435:   } else v = originalv;

437:   if (ishdf5) {
438: #if defined(PETSC_HAVE_HDF5)
439:     VecView_Plex_HDF5_Native_Internal(v, viewer);
440: #else
441:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
442: #endif
443:   } else if (isvtk) {
444:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
445:   } else {
446:     PetscBool isseq;

448:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
449:     if (isseq) {VecView_Seq(v, viewer);}
450:     else       {VecView_MPI(v, viewer);}
451:   }
452:   if (v != originalv) {DMRestoreGlobalVector(dm, &v);}
453:   return(0);
454: }

456: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
457: {
458:   DM             dm;
459:   PetscBool      ishdf5;

463:   VecGetDM(v, &dm);
464:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
465:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
466:   if (ishdf5) {
467:     DM          dmBC;
468:     Vec         gv;
469:     const char *name;

471:     DMGetOutputDM(dm, &dmBC);
472:     DMGetGlobalVector(dmBC, &gv);
473:     PetscObjectGetName((PetscObject) v, &name);
474:     PetscObjectSetName((PetscObject) gv, name);
475:     VecLoad_Default(gv, viewer);
476:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
477:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
478:     DMRestoreGlobalVector(dmBC, &gv);
479:   } else {
480:     VecLoad_Default(v, viewer);
481:   }
482:   return(0);
483: }

485: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
486: {
487:   DM             dm;
488:   PetscBool      ishdf5;

492:   VecGetDM(v, &dm);
493:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
494:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
495:   if (ishdf5) {
496: #if defined(PETSC_HAVE_HDF5)
497:     VecLoad_Plex_HDF5_Internal(v, viewer);
498: #else
499:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
500: #endif
501:   } else {
502:     VecLoad_Default(v, viewer);
503:   }
504:   return(0);
505: }

507: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
508: {
509:   DM                dm;
510:   PetscViewerFormat format;
511:   PetscBool         ishdf5;
512:   PetscErrorCode    ierr;

515:   VecGetDM(originalv, &dm);
516:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
517:   PetscViewerGetFormat(viewer, &format);
518:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
519:   if (format == PETSC_VIEWER_NATIVE) {
520:     if (dm->useNatural) {
521:       if (dm->sfNatural) {
522:         if (ishdf5) {
523: #if defined(PETSC_HAVE_HDF5)
524:           Vec         v;
525:           const char *vecname;

527:           DMGetGlobalVector(dm, &v);
528:           PetscObjectGetName((PetscObject) originalv, &vecname);
529:           PetscObjectSetName((PetscObject) v, vecname);
530:           VecLoad_Plex_HDF5_Native_Internal(v, viewer);
531:           DMPlexNaturalToGlobalBegin(dm, v, originalv);
532:           DMPlexNaturalToGlobalEnd(dm, v, originalv);
533:           DMRestoreGlobalVector(dm, &v);
534: #else
535:           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
536: #endif
537:         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
538:       }
539:     } else {
540:       VecLoad_Default(originalv, viewer);
541:     }
542:   }
543:   return(0);
544: }

546: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
547: {
548:   PetscSection       coordSection;
549:   Vec                coordinates;
550:   DMLabel            depthLabel;
551:   const char        *name[4];
552:   const PetscScalar *a;
553:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
554:   PetscErrorCode     ierr;

557:   DMGetDimension(dm, &dim);
558:   DMGetCoordinatesLocal(dm, &coordinates);
559:   DMGetCoordinateSection(dm, &coordSection);
560:   DMPlexGetDepthLabel(dm, &depthLabel);
561:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
562:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
563:   VecGetArrayRead(coordinates, &a);
564:   name[0]     = "vertex";
565:   name[1]     = "edge";
566:   name[dim-1] = "face";
567:   name[dim]   = "cell";
568:   for (c = cStart; c < cEnd; ++c) {
569:     PetscInt *closure = NULL;
570:     PetscInt  closureSize, cl;

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

578:       if ((point < pStart) || (point >= pEnd)) continue;
579:       PetscSectionGetDof(coordSection, point, &dof);
580:       if (!dof) continue;
581:       DMLabelGetValue(depthLabel, point, &depth);
582:       PetscSectionGetOffset(coordSection, point, &off);
583:       PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);
584:       for (p = 0; p < dof/dim; ++p) {
585:         PetscViewerASCIIPrintf(viewer, " (");
586:         for (d = 0; d < dim; ++d) {
587:           if (d > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
588:           PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));
589:         }
590:         PetscViewerASCIIPrintf(viewer, ")");
591:       }
592:       PetscViewerASCIIPrintf(viewer, "\n");
593:     }
594:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
595:     PetscViewerASCIIPopTab(viewer);
596:   }
597:   VecRestoreArrayRead(coordinates, &a);
598:   return(0);
599: }

601: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
602: {
603:   DM_Plex          *mesh = (DM_Plex*) dm->data;
604:   DM                cdm;
605:   DMLabel           markers;
606:   PetscSection      coordSection;
607:   Vec               coordinates;
608:   PetscViewerFormat format;
609:   PetscErrorCode    ierr;

612:   DMGetCoordinateDM(dm, &cdm);
613:   DMGetSection(cdm, &coordSection);
614:   DMGetCoordinatesLocal(dm, &coordinates);
615:   PetscViewerGetFormat(viewer, &format);
616:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
617:     const char *name;
618:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
619:     PetscInt    pStart, pEnd, p;
620:     PetscMPIInt rank, size;

622:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
623:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
624:     PetscObjectGetName((PetscObject) dm, &name);
625:     DMPlexGetChart(dm, &pStart, &pEnd);
626:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
627:     DMGetDimension(dm, &dim);
628:     DMPlexGetVTKCellHeight(dm, &cellHeight);
629:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
630:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
631:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
632:     PetscViewerASCIIPrintf(viewer, "Supports:\n", name);
633:     PetscViewerASCIIPushSynchronized(viewer);
634:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);
635:     for (p = pStart; p < pEnd; ++p) {
636:       PetscInt dof, off, s;

638:       PetscSectionGetDof(mesh->supportSection, p, &dof);
639:       PetscSectionGetOffset(mesh->supportSection, p, &off);
640:       for (s = off; s < off+dof; ++s) {
641:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
642:       }
643:     }
644:     PetscViewerFlush(viewer);
645:     PetscViewerASCIIPrintf(viewer, "Cones:\n", name);
646:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);
647:     for (p = pStart; p < pEnd; ++p) {
648:       PetscInt dof, off, c;

650:       PetscSectionGetDof(mesh->coneSection, p, &dof);
651:       PetscSectionGetOffset(mesh->coneSection, p, &off);
652:       for (c = off; c < off+dof; ++c) {
653:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
654:       }
655:     }
656:     PetscViewerFlush(viewer);
657:     PetscViewerASCIIPopSynchronized(viewer);
658:     if (coordSection && coordinates) {
659:       PetscSectionVecView(coordSection, coordinates, viewer);
660:     }
661:     DMGetLabel(dm, "marker", &markers);
662:     if (markers) {DMLabelView(markers,viewer);}
663:     if (size > 1) {
664:       PetscSF sf;

666:       DMGetPointSF(dm, &sf);
667:       PetscSFView(sf, viewer);
668:     }
669:     PetscViewerFlush(viewer);
670:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
671:     const char  *name, *color;
672:     const char  *defcolors[3]  = {"gray", "orange", "green"};
673:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
674:     PetscReal    scale         = 2.0;
675:     PetscReal    tikzscale     = 1.0;
676:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
677:     double       tcoords[3];
678:     PetscScalar *coords;
679:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
680:     PetscMPIInt  rank, size;
681:     char         **names, **colors, **lcolors;
682:     PetscBool    plotEdges, flg;

684:     DMGetDimension(dm, &dim);
685:     DMPlexGetDepth(dm, &depth);
686:     DMGetNumLabels(dm, &numLabels);
687:     numLabels  = PetscMax(numLabels, 10);
688:     numColors  = 10;
689:     numLColors = 10;
690:     PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);
691:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);
692:     PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);
693:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);
694:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);
695:     if (!useLabels) numLabels = 0;
696:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);
697:     if (!useColors) {
698:       numColors = 3;
699:       for (c = 0; c < numColors; ++c) {PetscStrallocpy(defcolors[c], &colors[c]);}
700:     }
701:     PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);
702:     if (!useColors) {
703:       numLColors = 4;
704:       for (c = 0; c < numLColors; ++c) {PetscStrallocpy(deflcolors[c], &lcolors[c]);}
705:     }
706:     plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3);
707:     PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);
708:     if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
709:     if (depth < dim) plotEdges = PETSC_FALSE;
710:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
711:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
712:     PetscObjectGetName((PetscObject) dm, &name);
713:     PetscViewerASCIIPrintf(viewer, "\
714: \\documentclass[tikz]{standalone}\n\n\
715: \\usepackage{pgflibraryshapes}\n\
716: \\usetikzlibrary{backgrounds}\n\
717: \\usetikzlibrary{arrows}\n\
718: \\begin{document}\n");
719:     if (size > 1) {
720:       PetscViewerASCIIPrintf(viewer, "%s for process ", name);
721:       for (p = 0; p < size; ++p) {
722:         if (p > 0 && p == size-1) {
723:           PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
724:         } else if (p > 0) {
725:           PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
726:         }
727:         PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
728:       }
729:       PetscViewerASCIIPrintf(viewer, ".\n\n\n");
730:     }
731:     PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", tikzscale);
732:     /* Plot vertices */
733:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
734:     VecGetArray(coordinates, &coords);
735:     PetscViewerASCIIPushSynchronized(viewer);
736:     for (v = vStart; v < vEnd; ++v) {
737:       PetscInt  off, dof, d;
738:       PetscBool isLabeled = PETSC_FALSE;

740:       PetscSectionGetDof(coordSection, v, &dof);
741:       PetscSectionGetOffset(coordSection, v, &off);
742:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
743:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
744:       for (d = 0; d < dof; ++d) {
745:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
746:         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
747:       }
748:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
749:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
750:       for (d = 0; d < dof; ++d) {
751:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
752:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
753:       }
754:       color = colors[rank%numColors];
755:       for (l = 0; l < numLabels; ++l) {
756:         PetscInt val;
757:         DMGetLabelValue(dm, names[l], v, &val);
758:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
759:       }
760:       if (useNumbers) {
761:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
762:       } else {
763:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
764:       }
765:     }
766:     VecRestoreArray(coordinates, &coords);
767:     PetscViewerFlush(viewer);
768:     /* Plot cells */
769:     DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
770:     DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
771:     if (dim == 3 || !useNumbers) {
772:       for (e = eStart; e < eEnd; ++e) {
773:         const PetscInt *cone;

775:         color = colors[rank%numColors];
776:         for (l = 0; l < numLabels; ++l) {
777:           PetscInt val;
778:           DMGetLabelValue(dm, names[l], e, &val);
779:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
780:         }
781:         DMPlexGetCone(dm, e, &cone);
782:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
783:       }
784:     } else {
785:       for (c = cStart; c < cEnd; ++c) {
786:         PetscInt *closure = NULL;
787:         PetscInt  closureSize, firstPoint = -1;

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

794:           if ((point < vStart) || (point >= vEnd)) continue;
795:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
796:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
797:           if (firstPoint < 0) firstPoint = point;
798:         }
799:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
800:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
801:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
802:       }
803:     }
804:     VecGetArray(coordinates, &coords);
805:     for (c = cStart; c < cEnd; ++c) {
806:       double    ccoords[3] = {0.0, 0.0, 0.0};
807:       PetscBool isLabeled  = PETSC_FALSE;
808:       PetscInt *closure    = NULL;
809:       PetscInt  closureSize, dof, d, n = 0;

811:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
812:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
813:       for (p = 0; p < closureSize*2; p += 2) {
814:         const PetscInt point = closure[p];
815:         PetscInt       off;

817:         if ((point < vStart) || (point >= vEnd)) continue;
818:         PetscSectionGetDof(coordSection, point, &dof);
819:         PetscSectionGetOffset(coordSection, point, &off);
820:         for (d = 0; d < dof; ++d) {
821:           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
822:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
823:         }
824:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
825:         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
826:         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
827:         ++n;
828:       }
829:       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
830:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
831:       for (d = 0; d < dof; ++d) {
832:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
833:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d]);
834:       }
835:       color = colors[rank%numColors];
836:       for (l = 0; l < numLabels; ++l) {
837:         PetscInt val;
838:         DMGetLabelValue(dm, names[l], c, &val);
839:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
840:       }
841:       if (useNumbers) {
842:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);
843:       } else {
844:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);
845:       }
846:     }
847:     VecRestoreArray(coordinates, &coords);
848:     /* Plot edges */
849:     if (plotEdges) {
850:       VecGetArray(coordinates, &coords);
851:       PetscViewerASCIIPrintf(viewer, "\\path\n");
852:       for (e = eStart; e < eEnd; ++e) {
853:         const PetscInt *cone;
854:         PetscInt        coneSize, offA, offB, dof, d;

856:         DMPlexGetConeSize(dm, e, &coneSize);
857:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
858:         DMPlexGetCone(dm, e, &cone);
859:         PetscSectionGetDof(coordSection, cone[0], &dof);
860:         PetscSectionGetOffset(coordSection, cone[0], &offA);
861:         PetscSectionGetOffset(coordSection, cone[1], &offB);
862:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
863:         for (d = 0; d < dof; ++d) {
864:           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
865:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
866:         }
867:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
868:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
869:         for (d = 0; d < dof; ++d) {
870:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
871:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
872:         }
873:         color = colors[rank%numColors];
874:         for (l = 0; l < numLabels; ++l) {
875:           PetscInt val;
876:           DMGetLabelValue(dm, names[l], v, &val);
877:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
878:         }
879:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
880:       }
881:       VecRestoreArray(coordinates, &coords);
882:       PetscViewerFlush(viewer);
883:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
884:     }
885:     PetscViewerFlush(viewer);
886:     PetscViewerASCIIPopSynchronized(viewer);
887:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
888:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
889:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
890:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
891:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
892:     PetscFree3(names, colors, lcolors);
893:   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
894:     Vec                    cown,acown;
895:     VecScatter             sct;
896:     ISLocalToGlobalMapping g2l;
897:     IS                     gid,acis;
898:     MPI_Comm               comm,ncomm = MPI_COMM_NULL;
899:     MPI_Group              ggroup,ngroup;
900:     PetscScalar            *array,nid;
901:     const PetscInt         *idxs;
902:     PetscInt               *idxs2,*start,*adjacency,*work;
903:     PetscInt64             lm[3],gm[3];
904:     PetscInt               i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
905:     PetscMPIInt            d1,d2,rank;

907:     PetscObjectGetComm((PetscObject)dm,&comm);
908:     MPI_Comm_rank(comm,&rank);
909: #if defined(PETSC_HAVE_MPI_SHARED_COMM)
910:     MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);
911: #endif
912:     if (ncomm != MPI_COMM_NULL) {
913:       MPI_Comm_group(comm,&ggroup);
914:       MPI_Comm_group(ncomm,&ngroup);
915:       d1   = 0;
916:       MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);
917:       nid  = d2;
918:       MPI_Group_free(&ggroup);
919:       MPI_Group_free(&ngroup);
920:       MPI_Comm_free(&ncomm);
921:     } else nid = 0.0;

923:     /* Get connectivity */
924:     DMPlexGetVTKCellHeight(dm,&cellHeight);
925:     DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);

927:     /* filter overlapped local cells */
928:     DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);
929:     ISGetIndices(gid,&idxs);
930:     ISGetLocalSize(gid,&cum);
931:     PetscMalloc1(cum,&idxs2);
932:     for (c = cStart, cum = 0; c < cEnd; c++) {
933:       if (idxs[c-cStart] < 0) continue;
934:       idxs2[cum++] = idxs[c-cStart];
935:     }
936:     ISRestoreIndices(gid,&idxs);
937:     if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum);
938:     ISDestroy(&gid);
939:     ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);

941:     /* support for node-aware cell locality */
942:     ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);
943:     VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);
944:     VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);
945:     VecGetArray(cown,&array);
946:     for (c = 0; c < numVertices; c++) array[c] = nid;
947:     VecRestoreArray(cown,&array);
948:     VecScatterCreate(cown,acis,acown,NULL,&sct);
949:     VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);
950:     VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);
951:     ISDestroy(&acis);
952:     VecScatterDestroy(&sct);
953:     VecDestroy(&cown);

955:     /* compute edgeCut */
956:     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
957:     PetscMalloc1(cum,&work);
958:     ISLocalToGlobalMappingCreateIS(gid,&g2l);
959:     ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);
960:     ISDestroy(&gid);
961:     VecGetArray(acown,&array);
962:     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
963:       PetscInt totl;

965:       totl = start[c+1]-start[c];
966:       ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);
967:       for (i = 0; i < totl; i++) {
968:         if (work[i] < 0) {
969:           ect  += 1;
970:           ectn += (array[i + start[c]] != nid) ? 0 : 1;
971:         }
972:       }
973:     }
974:     PetscFree(work);
975:     VecRestoreArray(acown,&array);
976:     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
977:     lm[1] = -numVertices;
978:     MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);
979:     PetscViewerASCIIPrintf(viewer,"  Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);
980:     lm[0] = ect; /* edgeCut */
981:     lm[1] = ectn; /* node-aware edgeCut */
982:     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
983:     MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);
984:     PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);
985: #if defined(PETSC_HAVE_MPI_SHARED_COMM)
986:     PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.);
987: #else
988:     PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);
989: #endif
990:     ISLocalToGlobalMappingDestroy(&g2l);
991:     PetscFree(start);
992:     PetscFree(adjacency);
993:     VecDestroy(&acown);
994:   } else {
995:     MPI_Comm    comm;
996:     PetscInt   *sizes, *hybsizes;
997:     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
998:     PetscInt    pStart, pEnd, p;
999:     PetscInt    numLabels, l;
1000:     const char *name;
1001:     PetscMPIInt size;

1003:     PetscObjectGetComm((PetscObject)dm,&comm);
1004:     MPI_Comm_size(comm, &size);
1005:     DMGetDimension(dm, &dim);
1006:     DMPlexGetVTKCellHeight(dm, &cellHeight);
1007:     PetscObjectGetName((PetscObject) dm, &name);
1008:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
1009:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
1010:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
1011:     DMPlexGetDepth(dm, &locDepth);
1012:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
1013:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);
1014:     PetscCalloc2(size,&sizes,size,&hybsizes);
1015:     if (depth == 1) {
1016:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
1017:       pEnd = pEnd - pStart;
1018:       pMax[0] -= pStart;
1019:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1020:       MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1021:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
1022:       for (p = 0; p < size; ++p) {
1023:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1024:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1025:       }
1026:       PetscViewerASCIIPrintf(viewer, "\n");
1027:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
1028:       pEnd = pEnd - pStart;
1029:       pMax[depth] -= pStart;
1030:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1031:       MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1032:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
1033:       for (p = 0; p < size; ++p) {
1034:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1035:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1036:       }
1037:       PetscViewerASCIIPrintf(viewer, "\n");
1038:     } else {
1039:       PetscMPIInt rank;
1040:       MPI_Comm_rank(comm, &rank);
1041:       for (d = 0; d <= dim; d++) {
1042:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
1043:         pEnd    -= pStart;
1044:         pMax[d] -= pStart;
1045:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
1046:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
1047:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
1048:         for (p = 0; p < size; ++p) {
1049:           if (!rank) {
1050:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
1051:             else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
1052:           }
1053:         }
1054:         PetscViewerASCIIPrintf(viewer, "\n");
1055:       }
1056:     }
1057:     PetscFree2(sizes,hybsizes);
1058:     DMGetNumLabels(dm, &numLabels);
1059:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
1060:     for (l = 0; l < numLabels; ++l) {
1061:       DMLabel         label;
1062:       const char     *name;
1063:       IS              valueIS;
1064:       const PetscInt *values;
1065:       PetscInt        numValues, v;

1067:       DMGetLabelName(dm, l, &name);
1068:       DMGetLabel(dm, name, &label);
1069:       DMLabelGetNumValues(label, &numValues);
1070:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
1071:       DMLabelGetValueIS(label, &valueIS);
1072:       ISGetIndices(valueIS, &values);
1073:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
1074:       for (v = 0; v < numValues; ++v) {
1075:         PetscInt size;

1077:         DMLabelGetStratumSize(label, values[v], &size);
1078:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
1079:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
1080:       }
1081:       PetscViewerASCIIPrintf(viewer, ")\n");
1082:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
1083:       ISRestoreIndices(valueIS, &values);
1084:       ISDestroy(&valueIS);
1085:     }
1086:     /* If no fields are specified, people do not want to see adjacency */
1087:     if (dm->Nf) {
1088:       PetscInt f;

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

1093:         PetscObjectGetName(dm->fields[f].disc, &name);
1094:         if (numLabels) {PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);}
1095:         PetscViewerASCIIPushTab(viewer);
1096:         if (dm->fields[f].label) {DMLabelView(dm->fields[f].label, viewer);}
1097:         if (dm->fields[f].adjacency[0]) {
1098:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");}
1099:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");}
1100:         } else {
1101:           if (dm->fields[f].adjacency[1]) {PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");}
1102:           else                            {PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");}
1103:         }
1104:         PetscViewerASCIIPopTab(viewer);
1105:       }
1106:     }
1107:     DMGetCoarseDM(dm, &cdm);
1108:     if (cdm) {
1109:       PetscViewerASCIIPushTab(viewer);
1110:       DMPlexView_Ascii(cdm, viewer);
1111:       PetscViewerASCIIPopTab(viewer);
1112:     }
1113:   }
1114:   return(0);
1115: }

1117: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1118: {
1119:   PetscDraw          draw;
1120:   DM                 cdm;
1121:   PetscSection       coordSection;
1122:   Vec                coordinates;
1123:   const PetscScalar *coords;
1124:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1125:   PetscBool          isnull;
1126:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
1127:   PetscMPIInt        rank;
1128:   PetscErrorCode     ierr;

1131:   DMGetCoordinateDim(dm, &dim);
1132:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1133:   DMGetCoordinateDM(dm, &cdm);
1134:   DMGetSection(cdm, &coordSection);
1135:   DMGetCoordinatesLocal(dm, &coordinates);
1136:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1137:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

1139:   PetscViewerDrawGetDraw(viewer, 0, &draw);
1140:   PetscDrawIsNull(draw, &isnull);
1141:   if (isnull) return(0);
1142:   PetscDrawSetTitle(draw, "Mesh");

1144:   VecGetLocalSize(coordinates, &N);
1145:   VecGetArrayRead(coordinates, &coords);
1146:   for (c = 0; c < N; c += dim) {
1147:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1148:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1149:   }
1150:   VecRestoreArrayRead(coordinates, &coords);
1151:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1152:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1153:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1154:   PetscDrawClear(draw);

1156:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1157:   for (c = cStart; c < cEnd; ++c) {
1158:     PetscScalar *coords = NULL;
1159:     PetscInt     numCoords,coneSize;

1161:     DMPlexGetConeSize(dm, c, &coneSize);
1162:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1163:     switch (coneSize) {
1164:     case 3:
1165:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1166:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1167:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1168:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1169:       break;
1170:     case 4:
1171:       PetscDrawRectangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1172:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1173:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1174:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1175:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1176:       break;
1177:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1178:     }
1179:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1180:   }
1181:   for (c = cStart; c < cEnd; ++c) {
1182:     PetscScalar *coords = NULL;
1183:     PetscInt     numCoords,coneSize;

1185:     DMPlexGetConeSize(dm, c, &coneSize);
1186:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1187:     switch (coneSize) {
1188:     case 3:
1189:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1190:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1191:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1192:       break;
1193:     case 4:
1194:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1195:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1196:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
1197:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1198:       break;
1199:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1200:     }
1201:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1202:   }
1203:   PetscDrawFlush(draw);
1204:   PetscDrawPause(draw);
1205:   PetscDrawSave(draw);
1206:   return(0);
1207: }

1209: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1210: {
1211:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1212:   char           name[PETSC_MAX_PATH_LEN];

1218:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
1219:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
1220:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
1221:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
1222:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
1223:   if (iascii) {
1224:     PetscViewerFormat format;
1225:     PetscViewerGetFormat(viewer, &format);
1226:     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1227:       DMPlexView_GLVis(dm, viewer);
1228:     } else {
1229:       DMPlexView_Ascii(dm, viewer);
1230:     }
1231:   } else if (ishdf5) {
1232: #if defined(PETSC_HAVE_HDF5)
1233:     DMPlexView_HDF5_Internal(dm, viewer);
1234: #else
1235:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1236: #endif
1237:   } else if (isvtk) {
1238:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
1239:   } else if (isdraw) {
1240:     DMPlexView_Draw(dm, viewer);
1241:   } else if (isglvis) {
1242:     DMPlexView_GLVis(dm, viewer);
1243:   } else {
1244:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1245:   }
1246:   /* Optionally view the partition */
1247:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1248:   if (flg) {
1249:     Vec ranks;
1250:     DMPlexCreateRankField(dm, &ranks);
1251:     VecView(ranks, viewer);
1252:     VecDestroy(&ranks);
1253:   }
1254:   /* Optionally view a label */
1255:   PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, PETSC_MAX_PATH_LEN, &flg);
1256:   if (flg) {
1257:     DMLabel label;
1258:     Vec     val;

1260:     DMGetLabel(dm, name, &label);
1261:     if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1262:     DMPlexCreateLabelField(dm, label, &val);
1263:     VecView(val, viewer);
1264:     VecDestroy(&val);
1265:   }
1266:   return(0);
1267: }

1269: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1270: {
1271:   PetscBool      ishdf5;

1277:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
1278:   if (ishdf5) {
1279: #if defined(PETSC_HAVE_HDF5)
1280:     PetscViewerFormat format;
1281:     PetscViewerGetFormat(viewer, &format);
1282:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1283:       DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
1284:     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1285:       DMPlexLoad_HDF5_Internal(dm, viewer);
1286:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1287: #else
1288:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1289: #endif
1290:   } else {
1291:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1292:   }
1293:   return(0);
1294: }

1296: PetscErrorCode DMDestroy_Plex(DM dm)
1297: {
1298:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1302:   PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1303:   PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1304:   if (--mesh->refct > 0) return(0);
1305:   PetscSectionDestroy(&mesh->coneSection);
1306:   PetscFree(mesh->cones);
1307:   PetscFree(mesh->coneOrientations);
1308:   PetscSectionDestroy(&mesh->supportSection);
1309:   PetscSectionDestroy(&mesh->subdomainSection);
1310:   PetscFree(mesh->supports);
1311:   PetscFree(mesh->facesTmp);
1312:   PetscFree(mesh->tetgenOpts);
1313:   PetscFree(mesh->triangleOpts);
1314:   PetscPartitionerDestroy(&mesh->partitioner);
1315:   DMLabelDestroy(&mesh->subpointMap);
1316:   ISDestroy(&mesh->globalVertexNumbers);
1317:   ISDestroy(&mesh->globalCellNumbers);
1318:   PetscSectionDestroy(&mesh->anchorSection);
1319:   ISDestroy(&mesh->anchorIS);
1320:   PetscSectionDestroy(&mesh->parentSection);
1321:   PetscFree(mesh->parents);
1322:   PetscFree(mesh->childIDs);
1323:   PetscSectionDestroy(&mesh->childSection);
1324:   PetscFree(mesh->children);
1325:   DMDestroy(&mesh->referenceTree);
1326:   PetscGridHashDestroy(&mesh->lbox);
1327:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1328:   PetscFree(mesh);
1329:   return(0);
1330: }

1332: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1333: {
1334:   PetscSection           sectionGlobal;
1335:   PetscInt               bs = -1, mbs;
1336:   PetscInt               localSize;
1337:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1338:   PetscErrorCode         ierr;
1339:   MatType                mtype;
1340:   ISLocalToGlobalMapping ltog;

1343:   MatInitializePackage();
1344:   mtype = dm->mattype;
1345:   DMGetGlobalSection(dm, &sectionGlobal);
1346:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1347:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1348:   MatCreate(PetscObjectComm((PetscObject)dm), J);
1349:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1350:   MatSetType(*J, mtype);
1351:   MatSetFromOptions(*J);
1352:   MatGetBlockSize(*J, &mbs);
1353:   if (mbs > 1) bs = mbs;
1354:   PetscStrcmp(mtype, MATSHELL, &isShell);
1355:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
1356:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1357:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1358:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1359:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1360:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1361:   PetscStrcmp(mtype, MATIS, &isMatIS);
1362:   if (!isShell) {
1363:     PetscSection subSection;
1364:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1365:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1366:     PetscInt     pStart, pEnd, p, dof, cdof;

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

1373:       DMGetSection(dm, &section);
1374:       PetscSectionGetStorageSize(section, &size);
1375:       PetscMalloc1(size,&ltogidx);
1376:       DMPlexGetSubdomainSection(dm, &subSection);
1377:     } else {
1378:       DMGetLocalToGlobalMapping(dm,&ltog);
1379:     }
1380:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1381:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1382:       PetscInt bdof;

1384:       PetscSectionGetDof(sectionGlobal, p, &dof);
1385:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1386:       dof  = dof < 0 ? -(dof+1) : dof;
1387:       bdof = cdof && (dof-cdof) ? 1 : dof;
1388:       if (dof) {
1389:         if (bs < 0)          {bs = bdof;}
1390:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1391:       }
1392:       if (isMatIS) {
1393:         PetscInt loff,c,off;
1394:         PetscSectionGetOffset(subSection, p, &loff);
1395:         PetscSectionGetOffset(sectionGlobal, p, &off);
1396:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1397:       }
1398:     }
1399:     /* Must have same blocksize on all procs (some might have no points) */
1400:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1401:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1402:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1403:     else                            {bs = bsMinMax[0];}
1404:     bs = bs < 0 ? 1 : bs;
1405:     if (isMatIS) {
1406:       PetscInt l;
1407:       /* Must reduce indices by blocksize */
1408:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1409:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1410:     }
1411:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1412:     if (isMatIS) {
1413:       ISLocalToGlobalMappingDestroy(&ltog);
1414:     }
1415:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1416:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1417:     PetscFree4(dnz, onz, dnzu, onzu);
1418:   }
1419:   MatSetDM(*J, dm);
1420:   return(0);
1421: }

1423: /*@
1424:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1426:   Not collective

1428:   Input Parameter:
1429: . mesh - The DMPlex

1431:   Output Parameters:
1432: . subsection - The subdomain section

1434:   Level: developer

1436: .seealso:
1437: @*/
1438: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1439: {
1440:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1445:   if (!mesh->subdomainSection) {
1446:     PetscSection section;
1447:     PetscSF      sf;

1449:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1450:     DMGetSection(dm,&section);
1451:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1452:     PetscSFDestroy(&sf);
1453:   }
1454:   *subsection = mesh->subdomainSection;
1455:   return(0);
1456: }

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

1461:   Not collective

1463:   Input Parameter:
1464: . mesh - The DMPlex

1466:   Output Parameters:
1467: + pStart - The first mesh point
1468: - pEnd   - The upper bound for mesh points

1470:   Level: beginner

1472: .seealso: DMPlexCreate(), DMPlexSetChart()
1473: @*/
1474: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1475: {
1476:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1481:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1482:   return(0);
1483: }

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

1488:   Not collective

1490:   Input Parameters:
1491: + mesh - The DMPlex
1492: . pStart - The first mesh point
1493: - pEnd   - The upper bound for mesh points

1495:   Output Parameters:

1497:   Level: beginner

1499: .seealso: DMPlexCreate(), DMPlexGetChart()
1500: @*/
1501: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1502: {
1503:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1508:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1509:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1510:   return(0);
1511: }

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

1516:   Not collective

1518:   Input Parameters:
1519: + mesh - The DMPlex
1520: - p - The point, which must lie in the chart set with DMPlexSetChart()

1522:   Output Parameter:
1523: . size - The cone size for point p

1525:   Level: beginner

1527: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1528: @*/
1529: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1530: {
1531:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1537:   PetscSectionGetDof(mesh->coneSection, p, size);
1538:   return(0);
1539: }

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

1544:   Not collective

1546:   Input Parameters:
1547: + mesh - The DMPlex
1548: . p - The point, which must lie in the chart set with DMPlexSetChart()
1549: - size - The cone size for point p

1551:   Output Parameter:

1553:   Note:
1554:   This should be called after DMPlexSetChart().

1556:   Level: beginner

1558: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1559: @*/
1560: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1561: {
1562:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1569:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1570:   return(0);
1571: }

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

1576:   Not collective

1578:   Input Parameters:
1579: + mesh - The DMPlex
1580: . p - The point, which must lie in the chart set with DMPlexSetChart()
1581: - size - The additional cone size for point p

1583:   Output Parameter:

1585:   Note:
1586:   This should be called after DMPlexSetChart().

1588:   Level: beginner

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

1600:   PetscSectionAddDof(mesh->coneSection, p, size);
1601:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1603:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1604:   return(0);
1605: }

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

1610:   Not collective

1612:   Input Parameters:
1613: + dm - The DMPlex
1614: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1619:   Level: beginner

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

1625: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
1626: @*/
1627: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1628: {
1629:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1630:   PetscInt       off;

1636:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1637:   *cone = &mesh->cones[off];
1638:   return(0);
1639: }

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

1644:   Not collective

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

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

1654:   Level: intermediate

1656: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
1657: @*/
1658: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
1659: {
1660:   PetscSection        cs, newcs;
1661:   PetscInt            *cones;
1662:   PetscInt            *newarr=NULL;
1663:   PetscInt            n;
1664:   PetscErrorCode      ierr;

1667:   DMPlexGetCones(dm, &cones);
1668:   DMPlexGetConeSection(dm, &cs);
1669:   PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);
1670:   if (pConesSection) *pConesSection = newcs;
1671:   if (pCones) {
1672:     PetscSectionGetStorageSize(newcs, &n);
1673:     ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);
1674:   }
1675:   return(0);
1676: }

1678: static PetscErrorCode DMPlexGetConeRecursive_Private(DM dm, PetscInt *n_inout, const PetscInt points[], PetscInt *offset_inout, PetscInt buf[])
1679: {
1680:   PetscInt p, n, cn, i;
1681:   const PetscInt *cone;

1685:   n = *n_inout;
1686:   *n_inout = 0;
1687:   for (i=0; i<n; i++) {
1688:     p = points[i];
1689:     DMPlexGetConeSize(dm, p, &cn);
1690:     if (!cn) {
1691:       cn = 1;
1692:       if (buf) {
1693:         buf[*offset_inout] = p;
1694:         ++(*offset_inout);
1695:       }
1696:     } else {
1697:       DMPlexGetCone(dm, p, &cone);
1698:       DMPlexGetConeRecursive_Private(dm, &cn, cone, offset_inout, buf);
1699:     }
1700:     *n_inout += cn;
1701:   }
1702:   return(0);
1703: }

1705: /*@C
1706:   DMPlexGetConeRecursive - Like DMPlexGetConeTuple() but recursive, i.e. each cone point is expanded into a set of its own cone points until a vertex (DAG point with no cone) is reached.

1708:   Not collective

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

1714:   Output Parameter:
1715: . pCones - An array of recursively expanded cones, i.e. containing only vertices, and each of them can be present multiple times

1717:   Level: advanced

1719: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple()
1720: @*/
1721: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS p, IS *pCones)
1722: {
1723:   const PetscInt      *arr=NULL;
1724:   PetscInt            *cpoints=NULL;
1725:   PetscInt            n, cn;
1726:   PetscInt            zero;
1727:   PetscErrorCode      ierr;

1730:   ISGetLocalSize(p, &n);
1731:   ISGetIndices(p, &arr);
1732:   zero = 0;
1733:   /* first figure out the total number of returned points */
1734:   cn = n;
1735:   DMPlexGetConeRecursive_Private(dm, &cn, arr, &zero, NULL);
1736:   PetscMalloc1(cn, &cpoints);
1737:   /* now get recursive cones themselves */
1738:   DMPlexGetConeRecursive_Private(dm, &n, arr, &zero, cpoints);
1739:   ISCreateGeneral(PetscObjectComm((PetscObject)p), n, cpoints, PETSC_OWN_POINTER, pCones);
1740:   ISRestoreIndices(p, &arr);
1741:   return(0);
1742: }

1744: /*@
1745:   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

1747:   Not collective

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

1754:   Output Parameter:

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

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

1761:   Level: beginner

1763: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1764: @*/
1765: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1766: {
1767:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1768:   PetscInt       pStart, pEnd;
1769:   PetscInt       dof, off, c;

1774:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1775:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1777:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1778:   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);
1779:   for (c = 0; c < dof; ++c) {
1780:     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);
1781:     mesh->cones[off+c] = cone[c];
1782:   }
1783:   return(0);
1784: }

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

1789:   Not collective

1791:   Input Parameters:
1792: + mesh - The DMPlex
1793: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1801:   Level: beginner

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

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

1809: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1810: @*/
1811: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1812: {
1813:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1814:   PetscInt       off;

1819: #if defined(PETSC_USE_DEBUG)
1820:   {
1821:     PetscInt dof;
1822:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1824:   }
1825: #endif
1826:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1828:   *coneOrientation = &mesh->coneOrientations[off];
1829:   return(0);
1830: }

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

1835:   Not collective

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

1845:   Output Parameter:

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

1850:   Level: beginner

1852: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1853: @*/
1854: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1855: {
1856:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1857:   PetscInt       pStart, pEnd;
1858:   PetscInt       dof, off, c;

1863:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1864:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1866:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1867:   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);
1868:   for (c = 0; c < dof; ++c) {
1869:     PetscInt cdof, o = coneOrientation[c];

1871:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1872:     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);
1873:     mesh->coneOrientations[off+c] = o;
1874:   }
1875:   return(0);
1876: }

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

1881:   Not collective

1883:   Input Parameters:
1884: + mesh - The DMPlex
1885: . p - The point, which must lie in the chart set with DMPlexSetChart()
1886: . conePos - The local index in the cone where the point should be put
1887: - conePoint - The mesh point to insert

1889:   Level: beginner

1891: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1892: @*/
1893: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1894: {
1895:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1896:   PetscInt       pStart, pEnd;
1897:   PetscInt       dof, off;

1902:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1903:   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);
1904:   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);
1905:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1906:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1907:   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);
1908:   mesh->cones[off+conePos] = conePoint;
1909:   return(0);
1910: }

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

1915:   Not collective

1917:   Input Parameters:
1918: + mesh - The DMPlex
1919: . p - The point, which must lie in the chart set with DMPlexSetChart()
1920: . conePos - The local index in the cone where the point should be put
1921: - coneOrientation - The point orientation to insert

1923:   Level: beginner

1925: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1926: @*/
1927: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1928: {
1929:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1930:   PetscInt       pStart, pEnd;
1931:   PetscInt       dof, off;

1936:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1937:   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);
1938:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1939:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1940:   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);
1941:   mesh->coneOrientations[off+conePos] = coneOrientation;
1942:   return(0);
1943: }

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

1948:   Not collective

1950:   Input Parameters:
1951: + mesh - The DMPlex
1952: - p - The point, which must lie in the chart set with DMPlexSetChart()

1954:   Output Parameter:
1955: . size - The support size for point p

1957:   Level: beginner

1959: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1960: @*/
1961: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1962: {
1963:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1969:   PetscSectionGetDof(mesh->supportSection, p, size);
1970:   return(0);
1971: }

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

1976:   Not collective

1978:   Input Parameters:
1979: + mesh - The DMPlex
1980: . p - The point, which must lie in the chart set with DMPlexSetChart()
1981: - size - The support size for point p

1983:   Output Parameter:

1985:   Note:
1986:   This should be called after DMPlexSetChart().

1988:   Level: beginner

1990: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1991: @*/
1992: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1993: {
1994:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

2001:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
2002:   return(0);
2003: }

2005: /*@C
2006:   DMPlexGetSupport - Return the points on the out-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()

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

2017:   Level: beginner

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

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

2025: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2026: @*/
2027: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
2028: {
2029:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2030:   PetscInt       off;

2036:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2037:   *support = &mesh->supports[off];
2038:   return(0);
2039: }

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

2044:   Not collective

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

2051:   Output Parameter:

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

2056:   Level: beginner

2058: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
2059: @*/
2060: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
2061: {
2062:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2063:   PetscInt       pStart, pEnd;
2064:   PetscInt       dof, off, c;

2069:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2070:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2072:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2073:   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);
2074:   for (c = 0; c < dof; ++c) {
2075:     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);
2076:     mesh->supports[off+c] = support[c];
2077:   }
2078:   return(0);
2079: }

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

2084:   Not collective

2086:   Input Parameters:
2087: + mesh - The DMPlex
2088: . p - The point, which must lie in the chart set with DMPlexSetChart()
2089: . supportPos - The local index in the cone where the point should be put
2090: - supportPoint - The mesh point to insert

2092:   Level: beginner

2094: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2095: @*/
2096: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
2097: {
2098:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2099:   PetscInt       pStart, pEnd;
2100:   PetscInt       dof, off;

2105:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
2106:   PetscSectionGetDof(mesh->supportSection, p, &dof);
2107:   PetscSectionGetOffset(mesh->supportSection, p, &off);
2108:   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);
2109:   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);
2110:   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);
2111:   mesh->supports[off+supportPos] = supportPoint;
2112:   return(0);
2113: }

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

2118:   Not collective

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

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

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

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

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

2139:   Level: beginner

2141: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2142: @*/
2143: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2144: {
2145:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2146:   PetscInt       *closure, *fifo;
2147:   const PetscInt *tmp = NULL, *tmpO = NULL;
2148:   PetscInt        tmpSize, t;
2149:   PetscInt        depth       = 0, maxSize;
2150:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2151:   PetscErrorCode  ierr;

2155:   DMPlexGetDepth(dm, &depth);
2156:   /* This is only 1-level */
2157:   if (useCone) {
2158:     DMPlexGetConeSize(dm, p, &tmpSize);
2159:     DMPlexGetCone(dm, p, &tmp);
2160:     DMPlexGetConeOrientation(dm, p, &tmpO);
2161:   } else {
2162:     DMPlexGetSupportSize(dm, p, &tmpSize);
2163:     DMPlexGetSupport(dm, p, &tmp);
2164:   }
2165:   if (depth == 1) {
2166:     if (*points) {
2167:       closure = *points;
2168:     } else {
2169:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2170:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2171:     }
2172:     closure[0] = p; closure[1] = 0;
2173:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2174:       closure[closureSize]   = tmp[t];
2175:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2176:     }
2177:     if (numPoints) *numPoints = closureSize/2;
2178:     if (points)    *points    = closure;
2179:     return(0);
2180:   }
2181:   {
2182:     PetscInt c, coneSeries, s,supportSeries;

2184:     c = mesh->maxConeSize;
2185:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2186:     s = mesh->maxSupportSize;
2187:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2188:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2189:   }
2190:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2191:   if (*points) {
2192:     closure = *points;
2193:   } else {
2194:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2195:   }
2196:   closure[0] = p; closure[1] = 0;
2197:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2198:     const PetscInt cp = tmp[t];
2199:     const PetscInt co = tmpO ? tmpO[t] : 0;

2201:     closure[closureSize]   = cp;
2202:     closure[closureSize+1] = co;
2203:     fifo[fifoSize]         = cp;
2204:     fifo[fifoSize+1]       = co;
2205:   }
2206:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2207:   while (fifoSize - fifoStart) {
2208:     const PetscInt q   = fifo[fifoStart];
2209:     const PetscInt o   = fifo[fifoStart+1];
2210:     const PetscInt rev = o >= 0 ? 0 : 1;
2211:     const PetscInt off = rev ? -(o+1) : o;

2213:     if (useCone) {
2214:       DMPlexGetConeSize(dm, q, &tmpSize);
2215:       DMPlexGetCone(dm, q, &tmp);
2216:       DMPlexGetConeOrientation(dm, q, &tmpO);
2217:     } else {
2218:       DMPlexGetSupportSize(dm, q, &tmpSize);
2219:       DMPlexGetSupport(dm, q, &tmp);
2220:       tmpO = NULL;
2221:     }
2222:     for (t = 0; t < tmpSize; ++t) {
2223:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2224:       const PetscInt cp = tmp[i];
2225:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2226:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2227:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2228:       PetscInt       co = tmpO ? tmpO[i] : 0;
2229:       PetscInt       c;

2231:       if (rev) {
2232:         PetscInt childSize, coff;
2233:         DMPlexGetConeSize(dm, cp, &childSize);
2234:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2235:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2236:       }
2237:       /* Check for duplicate */
2238:       for (c = 0; c < closureSize; c += 2) {
2239:         if (closure[c] == cp) break;
2240:       }
2241:       if (c == closureSize) {
2242:         closure[closureSize]   = cp;
2243:         closure[closureSize+1] = co;
2244:         fifo[fifoSize]         = cp;
2245:         fifo[fifoSize+1]       = co;
2246:         closureSize           += 2;
2247:         fifoSize              += 2;
2248:       }
2249:     }
2250:     fifoStart += 2;
2251:   }
2252:   if (numPoints) *numPoints = closureSize/2;
2253:   if (points)    *points    = closure;
2254:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2255:   return(0);
2256: }

2258: /*@C
2259:   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

2261:   Not collective

2263:   Input Parameters:
2264: + mesh - The DMPlex
2265: . p - The point, which must lie in the chart set with DMPlexSetChart()
2266: . orientation - The orientation of the point
2267: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2268: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

2283:   Level: beginner

2285: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2286: @*/
2287: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2288: {
2289:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2290:   PetscInt       *closure, *fifo;
2291:   const PetscInt *tmp = NULL, *tmpO = NULL;
2292:   PetscInt        tmpSize, t;
2293:   PetscInt        depth       = 0, maxSize;
2294:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2295:   PetscErrorCode  ierr;

2299:   DMPlexGetDepth(dm, &depth);
2300:   /* This is only 1-level */
2301:   if (useCone) {
2302:     DMPlexGetConeSize(dm, p, &tmpSize);
2303:     DMPlexGetCone(dm, p, &tmp);
2304:     DMPlexGetConeOrientation(dm, p, &tmpO);
2305:   } else {
2306:     DMPlexGetSupportSize(dm, p, &tmpSize);
2307:     DMPlexGetSupport(dm, p, &tmp);
2308:   }
2309:   if (depth == 1) {
2310:     if (*points) {
2311:       closure = *points;
2312:     } else {
2313:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2314:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2315:     }
2316:     closure[0] = p; closure[1] = ornt;
2317:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2318:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2319:       closure[closureSize]   = tmp[i];
2320:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2321:     }
2322:     if (numPoints) *numPoints = closureSize/2;
2323:     if (points)    *points    = closure;
2324:     return(0);
2325:   }
2326:   {
2327:     PetscInt c, coneSeries, s,supportSeries;

2329:     c = mesh->maxConeSize;
2330:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2331:     s = mesh->maxSupportSize;
2332:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2333:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2334:   }
2335:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2336:   if (*points) {
2337:     closure = *points;
2338:   } else {
2339:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2340:   }
2341:   closure[0] = p; closure[1] = ornt;
2342:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2343:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2344:     const PetscInt cp = tmp[i];
2345:     PetscInt       co = tmpO ? tmpO[i] : 0;

2347:     if (ornt < 0) {
2348:       PetscInt childSize, coff;
2349:       DMPlexGetConeSize(dm, cp, &childSize);
2350:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2351:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2352:     }
2353:     closure[closureSize]   = cp;
2354:     closure[closureSize+1] = co;
2355:     fifo[fifoSize]         = cp;
2356:     fifo[fifoSize+1]       = co;
2357:   }
2358:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2359:   while (fifoSize - fifoStart) {
2360:     const PetscInt q   = fifo[fifoStart];
2361:     const PetscInt o   = fifo[fifoStart+1];
2362:     const PetscInt rev = o >= 0 ? 0 : 1;
2363:     const PetscInt off = rev ? -(o+1) : o;

2365:     if (useCone) {
2366:       DMPlexGetConeSize(dm, q, &tmpSize);
2367:       DMPlexGetCone(dm, q, &tmp);
2368:       DMPlexGetConeOrientation(dm, q, &tmpO);
2369:     } else {
2370:       DMPlexGetSupportSize(dm, q, &tmpSize);
2371:       DMPlexGetSupport(dm, q, &tmp);
2372:       tmpO = NULL;
2373:     }
2374:     for (t = 0; t < tmpSize; ++t) {
2375:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2376:       const PetscInt cp = tmp[i];
2377:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2378:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2379:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2380:       PetscInt       co = tmpO ? tmpO[i] : 0;
2381:       PetscInt       c;

2383:       if (rev) {
2384:         PetscInt childSize, coff;
2385:         DMPlexGetConeSize(dm, cp, &childSize);
2386:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2387:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2388:       }
2389:       /* Check for duplicate */
2390:       for (c = 0; c < closureSize; c += 2) {
2391:         if (closure[c] == cp) break;
2392:       }
2393:       if (c == closureSize) {
2394:         closure[closureSize]   = cp;
2395:         closure[closureSize+1] = co;
2396:         fifo[fifoSize]         = cp;
2397:         fifo[fifoSize+1]       = co;
2398:         closureSize           += 2;
2399:         fifoSize              += 2;
2400:       }
2401:     }
2402:     fifoStart += 2;
2403:   }
2404:   if (numPoints) *numPoints = closureSize/2;
2405:   if (points)    *points    = closure;
2406:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2407:   return(0);
2408: }

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

2413:   Not collective

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

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

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

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

2431:   Level: beginner

2433: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2434: @*/
2435: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2436: {

2443:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2444:   if (numPoints) *numPoints = 0;
2445:   return(0);
2446: }

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

2451:   Not collective

2453:   Input Parameter:
2454: . mesh - The DMPlex

2456:   Output Parameters:
2457: + maxConeSize - The maximum number of in-edges
2458: - maxSupportSize - The maximum number of out-edges

2460:   Level: beginner

2462: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2463: @*/
2464: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2465: {
2466:   DM_Plex *mesh = (DM_Plex*) dm->data;

2470:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2471:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2472:   return(0);
2473: }

2475: PetscErrorCode DMSetUp_Plex(DM dm)
2476: {
2477:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2478:   PetscInt       size;

2483:   PetscSectionSetUp(mesh->coneSection);
2484:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2485:   PetscMalloc1(size, &mesh->cones);
2486:   PetscCalloc1(size, &mesh->coneOrientations);
2487:   if (mesh->maxSupportSize) {
2488:     PetscSectionSetUp(mesh->supportSection);
2489:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2490:     PetscMalloc1(size, &mesh->supports);
2491:   }
2492:   return(0);
2493: }

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

2500:   if (subdm) {DMClone(dm, subdm);}
2501:   DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
2502:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2503:   if (dm->useNatural && dm->sfMigration) {
2504:     PetscSF        sfMigrationInv,sfNatural;
2505:     PetscSection   section, sectionSeq;

2507:     (*subdm)->sfMigration = dm->sfMigration;
2508:     PetscObjectReference((PetscObject) dm->sfMigration);
2509:     DMGetSection((*subdm), &section);
2510:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2511:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
2512:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2514:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2515:     (*subdm)->sfNatural = sfNatural;
2516:     PetscSectionDestroy(&sectionSeq);
2517:     PetscSFDestroy(&sfMigrationInv);
2518:   }
2519:   return(0);
2520: }

2522: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2523: {
2525:   PetscInt       i = 0;

2528:   DMClone(dms[0], superdm);
2529:   DMCreateSectionSuperDM(dms, len, is, superdm);
2530:   (*superdm)->useNatural = PETSC_FALSE;
2531:   for (i = 0; i < len; i++){
2532:     if (dms[i]->useNatural && dms[i]->sfMigration) {
2533:       PetscSF        sfMigrationInv,sfNatural;
2534:       PetscSection   section, sectionSeq;

2536:       (*superdm)->sfMigration = dms[i]->sfMigration;
2537:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
2538:       (*superdm)->useNatural = PETSC_TRUE;
2539:       DMGetSection((*superdm), &section);
2540:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2541:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
2542:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2544:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2545:       (*superdm)->sfNatural = sfNatural;
2546:       PetscSectionDestroy(&sectionSeq);
2547:       PetscSFDestroy(&sfMigrationInv);
2548:       break;
2549:     }
2550:   }
2551:   return(0);
2552: }

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

2557:   Not collective

2559:   Input Parameter:
2560: . mesh - The DMPlex

2562:   Output Parameter:

2564:   Note:
2565:   This should be called after all calls to DMPlexSetCone()

2567:   Level: beginner

2569: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2570: @*/
2571: PetscErrorCode DMPlexSymmetrize(DM dm)
2572: {
2573:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2574:   PetscInt      *offsets;
2575:   PetscInt       supportSize;
2576:   PetscInt       pStart, pEnd, p;

2581:   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2582:   PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);
2583:   /* Calculate support sizes */
2584:   DMPlexGetChart(dm, &pStart, &pEnd);
2585:   for (p = pStart; p < pEnd; ++p) {
2586:     PetscInt dof, off, c;

2588:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2589:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2590:     for (c = off; c < off+dof; ++c) {
2591:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2592:     }
2593:   }
2594:   for (p = pStart; p < pEnd; ++p) {
2595:     PetscInt dof;

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

2599:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2600:   }
2601:   PetscSectionSetUp(mesh->supportSection);
2602:   /* Calculate supports */
2603:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2604:   PetscMalloc1(supportSize, &mesh->supports);
2605:   PetscCalloc1(pEnd - pStart, &offsets);
2606:   for (p = pStart; p < pEnd; ++p) {
2607:     PetscInt dof, off, c;

2609:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2610:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2611:     for (c = off; c < off+dof; ++c) {
2612:       const PetscInt q = mesh->cones[c];
2613:       PetscInt       offS;

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

2617:       mesh->supports[offS+offsets[q]] = p;
2618:       ++offsets[q];
2619:     }
2620:   }
2621:   PetscFree(offsets);
2622:   PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);
2623:   return(0);
2624: }

2626: static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
2627: {
2628:   IS             stratumIS;

2632:   if (pStart >= pEnd) return(0);
2633: #if defined(PETSC_USE_DEBUG)
2634:   {
2635:     PetscInt  qStart, qEnd, numLevels, level;
2636:     PetscBool overlap = PETSC_FALSE;
2637:     DMLabelGetNumValues(label, &numLevels);
2638:     for (level = 0; level < numLevels; level++) {
2639:       DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2640:       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
2641:     }
2642:     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);
2643:   }
2644: #endif
2645:   ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);
2646:   DMLabelSetStratumIS(label, depth, stratumIS);
2647:   ISDestroy(&stratumIS);
2648:   return(0);
2649: }

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

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

2659:   Collective on dm

2661:   Input Parameter:
2662: . mesh - The DMPlex

2664:   Output Parameter:

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

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

2674:   Level: beginner

2676: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2677: @*/
2678: PetscErrorCode DMPlexStratify(DM dm)
2679: {
2680:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2681:   DMLabel        label;
2682:   PetscInt       pStart, pEnd, p;
2683:   PetscInt       numRoots = 0, numLeaves = 0;
2684:   PetscInt       cMax, fMax, eMax, vMax;

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

2691:   /* Create depth label */
2692:   DMPlexGetChart(dm, &pStart, &pEnd);
2693:   DMCreateLabel(dm, "depth");
2694:   DMPlexGetDepthLabel(dm, &label);

2696:   {
2697:     /* Initialize roots and count leaves */
2698:     PetscInt sMin = PETSC_MAX_INT;
2699:     PetscInt sMax = PETSC_MIN_INT;
2700:     PetscInt coneSize, supportSize;

2702:     for (p = pStart; p < pEnd; ++p) {
2703:       DMPlexGetConeSize(dm, p, &coneSize);
2704:       DMPlexGetSupportSize(dm, p, &supportSize);
2705:       if (!coneSize && supportSize) {
2706:         sMin = PetscMin(p, sMin);
2707:         sMax = PetscMax(p, sMax);
2708:         ++numRoots;
2709:       } else if (!supportSize && coneSize) {
2710:         ++numLeaves;
2711:       } else if (!supportSize && !coneSize) {
2712:         /* Isolated points */
2713:         sMin = PetscMin(p, sMin);
2714:         sMax = PetscMax(p, sMax);
2715:       }
2716:     }
2717:     DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);
2718:   }

2720:   if (numRoots + numLeaves == (pEnd - pStart)) {
2721:     PetscInt sMin = PETSC_MAX_INT;
2722:     PetscInt sMax = PETSC_MIN_INT;
2723:     PetscInt coneSize, supportSize;

2725:     for (p = pStart; p < pEnd; ++p) {
2726:       DMPlexGetConeSize(dm, p, &coneSize);
2727:       DMPlexGetSupportSize(dm, p, &supportSize);
2728:       if (!supportSize && coneSize) {
2729:         sMin = PetscMin(p, sMin);
2730:         sMax = PetscMax(p, sMax);
2731:       }
2732:     }
2733:     DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);
2734:   } else {
2735:     PetscInt level = 0;
2736:     PetscInt qStart, qEnd, q;

2738:     DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2739:     while (qEnd > qStart) {
2740:       PetscInt sMin = PETSC_MAX_INT;
2741:       PetscInt sMax = PETSC_MIN_INT;

2743:       for (q = qStart; q < qEnd; ++q) {
2744:         const PetscInt *support;
2745:         PetscInt        supportSize, s;

2747:         DMPlexGetSupportSize(dm, q, &supportSize);
2748:         DMPlexGetSupport(dm, q, &support);
2749:         for (s = 0; s < supportSize; ++s) {
2750:           sMin = PetscMin(support[s], sMin);
2751:           sMax = PetscMax(support[s], sMax);
2752:         }
2753:       }
2754:       DMLabelGetNumValues(label, &level);
2755:       DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);
2756:       DMLabelGetStratumBounds(label, level, &qStart, &qEnd);
2757:     }
2758:   }
2759:   { /* just in case there is an empty process */
2760:     PetscInt numValues, maxValues = 0, v;

2762:     DMLabelGetNumValues(label, &numValues);
2763:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2764:     for (v = numValues; v < maxValues; v++) {
2765:       DMLabelAddStratum(label, v);
2766:     }
2767:   }
2768:   PetscObjectStateGet((PetscObject) label, &mesh->depthState);

2770:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2771:   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2772:     PetscInt dim;
2773:     DMLabel  dimLabel;

2775:     DMGetDimension(dm, &dim);
2776:     DMCreateLabel(dm, "dim");
2777:     DMGetLabel(dm, "dim", &dimLabel);
2778:     if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2779:     if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2780:     if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2781:     if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2782:   }
2783:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2784:   return(0);
2785: }

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

2790:   Not Collective

2792:   Input Parameters:
2793: + dm - The DMPlex object
2794: . numPoints - The number of input points for the join
2795: - points - The input points

2797:   Output Parameters:
2798: + numCoveredPoints - The number of points in the join
2799: - coveredPoints - The points in the join

2801:   Level: intermediate

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

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

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

2811: .keywords: mesh
2812: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2813: @*/
2814: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2815: {
2816:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2817:   PetscInt      *join[2];
2818:   PetscInt       joinSize, i = 0;
2819:   PetscInt       dof, off, p, c, m;

2827:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2828:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2829:   /* Copy in support of first point */
2830:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2831:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2832:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2833:     join[i][joinSize] = mesh->supports[off+joinSize];
2834:   }
2835:   /* Check each successive support */
2836:   for (p = 1; p < numPoints; ++p) {
2837:     PetscInt newJoinSize = 0;

2839:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2840:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2841:     for (c = 0; c < dof; ++c) {
2842:       const PetscInt point = mesh->supports[off+c];

2844:       for (m = 0; m < joinSize; ++m) {
2845:         if (point == join[i][m]) {
2846:           join[1-i][newJoinSize++] = point;
2847:           break;
2848:         }
2849:       }
2850:     }
2851:     joinSize = newJoinSize;
2852:     i        = 1-i;
2853:   }
2854:   *numCoveredPoints = joinSize;
2855:   *coveredPoints    = join[i];
2856:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2857:   return(0);
2858: }

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

2863:   Not Collective

2865:   Input Parameters:
2866: + dm - The DMPlex object
2867: . numPoints - The number of input points for the join
2868: - points - The input points

2870:   Output Parameters:
2871: + numCoveredPoints - The number of points in the join
2872: - coveredPoints - The points in the join

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

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

2880:   Level: intermediate

2882: .keywords: mesh
2883: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2884: @*/
2885: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2886: {

2894:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2895:   if (numCoveredPoints) *numCoveredPoints = 0;
2896:   return(0);
2897: }

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

2902:   Not Collective

2904:   Input Parameters:
2905: + dm - The DMPlex object
2906: . numPoints - The number of input points for the join
2907: - points - The input points

2909:   Output Parameters:
2910: + numCoveredPoints - The number of points in the join
2911: - coveredPoints - The points in the join

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

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

2919:   Level: intermediate

2921: .keywords: mesh
2922: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2923: @*/
2924: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2925: {
2926:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2927:   PetscInt      *offsets, **closures;
2928:   PetscInt      *join[2];
2929:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2930:   PetscInt       p, d, c, m, ms;


2939:   DMPlexGetDepth(dm, &depth);
2940:   PetscCalloc1(numPoints, &closures);
2941:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2942:   ms      = mesh->maxSupportSize;
2943:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2944:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2945:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

2947:   for (p = 0; p < numPoints; ++p) {
2948:     PetscInt closureSize;

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

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

2956:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2957:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2958:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2959:           offsets[p*(depth+2)+d+1] = i;
2960:           break;
2961:         }
2962:       }
2963:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2964:     }
2965:     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);
2966:   }
2967:   for (d = 0; d < depth+1; ++d) {
2968:     PetscInt dof;

2970:     /* Copy in support of first point */
2971:     dof = offsets[d+1] - offsets[d];
2972:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2973:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2974:     }
2975:     /* Check each successive cone */
2976:     for (p = 1; p < numPoints && joinSize; ++p) {
2977:       PetscInt newJoinSize = 0;

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

2983:         for (m = 0; m < joinSize; ++m) {
2984:           if (point == join[i][m]) {
2985:             join[1-i][newJoinSize++] = point;
2986:             break;
2987:           }
2988:         }
2989:       }
2990:       joinSize = newJoinSize;
2991:       i        = 1-i;
2992:     }
2993:     if (joinSize) break;
2994:   }
2995:   *numCoveredPoints = joinSize;
2996:   *coveredPoints    = join[i];
2997:   for (p = 0; p < numPoints; ++p) {
2998:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2999:   }
3000:   PetscFree(closures);
3001:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
3002:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
3003:   return(0);
3004: }

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

3009:   Not Collective

3011:   Input Parameters:
3012: + dm - The DMPlex object
3013: . numPoints - The number of input points for the meet
3014: - points - The input points

3016:   Output Parameters:
3017: + numCoveredPoints - The number of points in the meet
3018: - coveredPoints - The points in the meet

3020:   Level: intermediate

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

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

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

3030: .keywords: mesh
3031: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
3032: @*/
3033: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
3034: {
3035:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3036:   PetscInt      *meet[2];
3037:   PetscInt       meetSize, i = 0;
3038:   PetscInt       dof, off, p, c, m;

3046:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
3047:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
3048:   /* Copy in cone of first point */
3049:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
3050:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
3051:   for (meetSize = 0; meetSize < dof; ++meetSize) {
3052:     meet[i][meetSize] = mesh->cones[off+meetSize];
3053:   }
3054:   /* Check each successive cone */
3055:   for (p = 1; p < numPoints; ++p) {
3056:     PetscInt newMeetSize = 0;

3058:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
3059:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
3060:     for (c = 0; c < dof; ++c) {
3061:       const PetscInt point = mesh->cones[off+c];

3063:       for (m = 0; m < meetSize; ++m) {
3064:         if (point == meet[i][m]) {
3065:           meet[1-i][newMeetSize++] = point;
3066:           break;
3067:         }
3068:       }
3069:     }
3070:     meetSize = newMeetSize;
3071:     i        = 1-i;
3072:   }
3073:   *numCoveringPoints = meetSize;
3074:   *coveringPoints    = meet[i];
3075:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3076:   return(0);
3077: }

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

3082:   Not Collective

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

3089:   Output Parameters:
3090: + numCoveredPoints - The number of points in the meet
3091: - coveredPoints - The points in the meet

3093:   Level: intermediate

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

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

3101: .keywords: mesh
3102: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
3103: @*/
3104: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3105: {

3113:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
3114:   if (numCoveredPoints) *numCoveredPoints = 0;
3115:   return(0);
3116: }

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

3121:   Not Collective

3123:   Input Parameters:
3124: + dm - The DMPlex object
3125: . numPoints - The number of input points for the meet
3126: - points - The input points

3128:   Output Parameters:
3129: + numCoveredPoints - The number of points in the meet
3130: - coveredPoints - The points in the meet

3132:   Level: intermediate

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

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

3140: .keywords: mesh
3141: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3142: @*/
3143: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3144: {
3145:   DM_Plex       *mesh = (DM_Plex*) dm->data;
3146:   PetscInt      *offsets, **closures;
3147:   PetscInt      *meet[2];
3148:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
3149:   PetscInt       p, h, c, m, mc;


3158:   DMPlexGetDepth(dm, &height);
3159:   PetscMalloc1(numPoints, &closures);
3160:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3161:   mc      = mesh->maxConeSize;
3162:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3163:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
3164:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

3166:   for (p = 0; p < numPoints; ++p) {
3167:     PetscInt closureSize;

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

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

3175:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
3176:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3177:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3178:           offsets[p*(height+2)+h+1] = i;
3179:           break;
3180:         }
3181:       }
3182:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3183:     }
3184:     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);
3185:   }
3186:   for (h = 0; h < height+1; ++h) {
3187:     PetscInt dof;

3189:     /* Copy in cone of first point */
3190:     dof = offsets[h+1] - offsets[h];
3191:     for (meetSize = 0; meetSize < dof; ++meetSize) {
3192:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3193:     }
3194:     /* Check each successive cone */
3195:     for (p = 1; p < numPoints && meetSize; ++p) {
3196:       PetscInt newMeetSize = 0;

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

3202:         for (m = 0; m < meetSize; ++m) {
3203:           if (point == meet[i][m]) {
3204:             meet[1-i][newMeetSize++] = point;
3205:             break;
3206:           }
3207:         }
3208:       }
3209:       meetSize = newMeetSize;
3210:       i        = 1-i;
3211:     }
3212:     if (meetSize) break;
3213:   }
3214:   *numCoveredPoints = meetSize;
3215:   *coveredPoints    = meet[i];
3216:   for (p = 0; p < numPoints; ++p) {
3217:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
3218:   }
3219:   PetscFree(closures);
3220:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
3221:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
3222:   return(0);
3223: }

3225: /*@C
3226:   DMPlexEqual - Determine if two DMs have the same topology

3228:   Not Collective

3230:   Input Parameters:
3231: + dmA - A DMPlex object
3232: - dmB - A DMPlex object

3234:   Output Parameters:
3235: . equal - PETSC_TRUE if the topologies are identical

3237:   Level: intermediate

3239:   Notes:
3240:   We are not solving graph isomorphism, so we do not permutation.

3242: .keywords: mesh
3243: .seealso: DMPlexGetCone()
3244: @*/
3245: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3246: {
3247:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


3255:   *equal = PETSC_FALSE;
3256:   DMPlexGetDepth(dmA, &depth);
3257:   DMPlexGetDepth(dmB, &depthB);
3258:   if (depth != depthB) return(0);
3259:   DMPlexGetChart(dmA, &pStart,  &pEnd);
3260:   DMPlexGetChart(dmB, &pStartB, &pEndB);
3261:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3262:   for (p = pStart; p < pEnd; ++p) {
3263:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3264:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

3266:     DMPlexGetConeSize(dmA, p, &coneSize);
3267:     DMPlexGetCone(dmA, p, &cone);
3268:     DMPlexGetConeOrientation(dmA, p, &ornt);
3269:     DMPlexGetConeSize(dmB, p, &coneSizeB);
3270:     DMPlexGetCone(dmB, p, &coneB);
3271:     DMPlexGetConeOrientation(dmB, p, &orntB);
3272:     if (coneSize != coneSizeB) return(0);
3273:     for (c = 0; c < coneSize; ++c) {
3274:       if (cone[c] != coneB[c]) return(0);
3275:       if (ornt[c] != orntB[c]) return(0);
3276:     }
3277:     DMPlexGetSupportSize(dmA, p, &supportSize);
3278:     DMPlexGetSupport(dmA, p, &support);
3279:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
3280:     DMPlexGetSupport(dmB, p, &supportB);
3281:     if (supportSize != supportSizeB) return(0);
3282:     for (s = 0; s < supportSize; ++s) {
3283:       if (support[s] != supportB[s]) return(0);
3284:     }
3285:   }
3286:   *equal = PETSC_TRUE;
3287:   return(0);
3288: }

3290: /*@C
3291:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

3293:   Not Collective

3295:   Input Parameters:
3296: + dm         - The DMPlex
3297: . cellDim    - The cell dimension
3298: - numCorners - The number of vertices on a cell

3300:   Output Parameters:
3301: . numFaceVertices - The number of vertices on a face

3303:   Level: developer

3305:   Notes:
3306:   Of course this can only work for a restricted set of symmetric shapes

3308: .seealso: DMPlexGetCone()
3309: @*/
3310: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3311: {
3312:   MPI_Comm       comm;

3316:   PetscObjectGetComm((PetscObject)dm,&comm);
3318:   switch (cellDim) {
3319:   case 0:
3320:     *numFaceVertices = 0;
3321:     break;
3322:   case 1:
3323:     *numFaceVertices = 1;
3324:     break;
3325:   case 2:
3326:     switch (numCorners) {
3327:     case 3: /* triangle */
3328:       *numFaceVertices = 2; /* Edge has 2 vertices */
3329:       break;
3330:     case 4: /* quadrilateral */
3331:       *numFaceVertices = 2; /* Edge has 2 vertices */
3332:       break;
3333:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3334:       *numFaceVertices = 3; /* Edge has 3 vertices */
3335:       break;
3336:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3337:       *numFaceVertices = 3; /* Edge has 3 vertices */
3338:       break;
3339:     default:
3340:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3341:     }
3342:     break;
3343:   case 3:
3344:     switch (numCorners) {
3345:     case 4: /* tetradehdron */
3346:       *numFaceVertices = 3; /* Face has 3 vertices */
3347:       break;
3348:     case 6: /* tet cohesive cells */
3349:       *numFaceVertices = 4; /* Face has 4 vertices */
3350:       break;
3351:     case 8: /* hexahedron */
3352:       *numFaceVertices = 4; /* Face has 4 vertices */
3353:       break;
3354:     case 9: /* tet cohesive Lagrange cells */
3355:       *numFaceVertices = 6; /* Face has 6 vertices */
3356:       break;
3357:     case 10: /* quadratic tetrahedron */
3358:       *numFaceVertices = 6; /* Face has 6 vertices */
3359:       break;
3360:     case 12: /* hex cohesive Lagrange cells */
3361:       *numFaceVertices = 6; /* Face has 6 vertices */
3362:       break;
3363:     case 18: /* quadratic tet cohesive Lagrange cells */
3364:       *numFaceVertices = 6; /* Face has 6 vertices */
3365:       break;
3366:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3367:       *numFaceVertices = 9; /* Face has 9 vertices */
3368:       break;
3369:     default:
3370:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3371:     }
3372:     break;
3373:   default:
3374:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3375:   }
3376:   return(0);
3377: }

3379: /*@
3380:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

3382:   Not Collective

3384:   Input Parameter:
3385: . dm    - The DMPlex object

3387:   Output Parameter:
3388: . depthLabel - The DMLabel recording point depth

3390:   Level: developer

3392: .keywords: mesh, points
3393: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3394: @*/
3395: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3396: {

3402:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3403:   *depthLabel = dm->depthLabel;
3404:   return(0);
3405: }

3407: /*@
3408:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

3410:   Not Collective

3412:   Input Parameter:
3413: . dm    - The DMPlex object

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

3418:   Level: developer

3420: .keywords: mesh, points
3421: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3422: @*/
3423: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3424: {
3425:   DMLabel        label;
3426:   PetscInt       d = 0;

3432:   DMPlexGetDepthLabel(dm, &label);
3433:   if (label) {DMLabelGetNumValues(label, &d);}
3434:   *depth = d-1;
3435:   return(0);
3436: }

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

3441:   Not Collective

3443:   Input Parameters:
3444: + dm           - The DMPlex object
3445: - stratumValue - The requested depth

3447:   Output Parameters:
3448: + start - The first point at this depth
3449: - end   - One beyond the last point at this depth

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

3456:   Level: developer

3458: .keywords: mesh, points
3459: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3460: @*/
3461: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3462: {
3463:   DMLabel        label;
3464:   PetscInt       pStart, pEnd;

3471:   DMPlexGetChart(dm, &pStart, &pEnd);
3472:   if (pStart == pEnd) return(0);
3473:   if (stratumValue < 0) {
3474:     if (start) *start = pStart;
3475:     if (end)   *end   = pEnd;
3476:     return(0);
3477:   }
3478:   DMPlexGetDepthLabel(dm, &label);
3479:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3480:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3481:   return(0);
3482: }

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

3487:   Not Collective

3489:   Input Parameters:
3490: + dm           - The DMPlex object
3491: - stratumValue - The requested height

3493:   Output Parameters:
3494: + start - The first point at this height
3495: - end   - One beyond the last point at this height

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

3502:   Level: developer

3504: .keywords: mesh, points
3505: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3506: @*/
3507: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3508: {
3509:   DMLabel        label;
3510:   PetscInt       depth, pStart, pEnd;

3517:   DMPlexGetChart(dm, &pStart, &pEnd);
3518:   if (pStart == pEnd) return(0);
3519:   if (stratumValue < 0) {
3520:     if (start) *start = pStart;
3521:     if (end)   *end   = pEnd;
3522:     return(0);
3523:   }
3524:   DMPlexGetDepthLabel(dm, &label);
3525:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3526:   DMLabelGetNumValues(label, &depth);
3527:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3528:   return(0);
3529: }

3531: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3532: {
3533:   PetscSection   section, s;
3534:   Mat            m;
3535:   PetscInt       maxHeight;

3539:   DMClone(dm, cdm);
3540:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3541:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3542:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3543:   DMSetSection(*cdm, section);
3544:   PetscSectionDestroy(&section);
3545:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3546:   MatCreate(PETSC_COMM_SELF, &m);
3547:   DMSetDefaultConstraints(*cdm, s, m);
3548:   PetscSectionDestroy(&s);
3549:   MatDestroy(&m);

3551:   DMSetNumFields(*cdm, 1);
3552:   DMCreateDS(*cdm);
3553:   return(0);
3554: }

3556: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3557: {
3558:   Vec            coordsLocal;
3559:   DM             coordsDM;

3563:   *field = NULL;
3564:   DMGetCoordinatesLocal(dm,&coordsLocal);
3565:   DMGetCoordinateDM(dm,&coordsDM);
3566:   if (coordsLocal && coordsDM) {
3567:     DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3568:   }
3569:   return(0);
3570: }

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

3575:   Not Collective

3577:   Input Parameters:
3578: . dm        - The DMPlex object

3580:   Output Parameter:
3581: . section - The PetscSection object

3583:   Level: developer

3585: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3586: @*/
3587: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3588: {
3589:   DM_Plex *mesh = (DM_Plex*) dm->data;

3593:   if (section) *section = mesh->coneSection;
3594:   return(0);
3595: }

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

3600:   Not Collective

3602:   Input Parameters:
3603: . dm        - The DMPlex object

3605:   Output Parameter:
3606: . section - The PetscSection object

3608:   Level: developer

3610: .seealso: DMPlexGetConeSection()
3611: @*/
3612: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3613: {
3614:   DM_Plex *mesh = (DM_Plex*) dm->data;

3618:   if (section) *section = mesh->supportSection;
3619:   return(0);
3620: }

3622: /*@C
3623:   DMPlexGetCones - Return cone data

3625:   Not Collective

3627:   Input Parameters:
3628: . dm        - The DMPlex object

3630:   Output Parameter:
3631: . cones - The cone for each point

3633:   Level: developer

3635: .seealso: DMPlexGetConeSection()
3636: @*/
3637: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3638: {
3639:   DM_Plex *mesh = (DM_Plex*) dm->data;

3643:   if (cones) *cones = mesh->cones;
3644:   return(0);
3645: }

3647: /*@C
3648:   DMPlexGetConeOrientations - Return cone orientation data

3650:   Not Collective

3652:   Input Parameters:
3653: . dm        - The DMPlex object

3655:   Output Parameter:
3656: . coneOrientations - The cone orientation for each point

3658:   Level: developer

3660: .seealso: DMPlexGetConeSection()
3661: @*/
3662: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3663: {
3664:   DM_Plex *mesh = (DM_Plex*) dm->data;

3668:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3669:   return(0);
3670: }

3672: /******************************** FEM Support **********************************/

3674: /*@

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

3680:   Input Parameters:
3681: + dm      - The DM
3682: . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
3683: - section - The PetscSection to reorder, or NULL for the default section

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

3688:   Example:
3689:   A typical interpolated single-quad mesh might order points as
3690: .vb
3691:   [c0, v1, v2, v3, v4, e5, e6, e7, e8]

3693:   v4 -- e6 -- v3
3694:   |           |
3695:   e7    c0    e8
3696:   |           |
3697:   v1 -- e5 -- v2
3698: .ve

3700:   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
3701:   dofs in the order of points, e.g.,
3702: .vb
3703:     c0 -> [0,1,2,3]
3704:     v1 -> [4]
3705:     ...
3706:     e5 -> [8, 9]
3707: .ve

3709:   which corresponds to the dofs
3710: .vb
3711:     6   10  11  7
3712:     13  2   3   15
3713:     12  0   1   14
3714:     4   8   9   5
3715: .ve

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

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

3727:   Level: developer

3729: .seealso: DMGetSection(), PetscSectionSetClosurePermutation()
3730: @*/
3731: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
3732: {
3733:   DMLabel        label;
3734:   PetscInt      *perm;
3735:   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3739:   if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3740:   DMGetDimension(dm, &dim);
3741:   DMPlexGetDepthLabel(dm, &label);
3742:   DMLabelGetValue(label, point, &depth);
3743:   if (depth == 1) {eStart = point;}
3744:   else if  (depth == dim) {
3745:     const PetscInt *cone;

3747:     DMPlexGetCone(dm, point, &cone);
3748:     if (dim == 2) eStart = cone[0];
3749:     else if (dim == 3) {
3750:       const PetscInt *cone2;
3751:       DMPlexGetCone(dm, cone[0], &cone2);
3752:       eStart = cone2[0];
3753:     } 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);
3754:   } 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);
3755:   if (!section) {DMGetSection(dm, &section);}
3756:   PetscSectionGetNumFields(section, &Nf);
3757:   if (dim < 1) return(0);
3758:   for (f = 0; f < Nf; ++f) {
3759:     /* An order k SEM disc has k-1 dofs on an edge */
3760:     PetscSectionGetFieldDof(section, eStart, f, &k);
3761:     PetscSectionGetFieldComponents(section, f, &Nc);
3762:     k = k/Nc + 1;
3763:     size += PetscPowInt(k+1, dim)*Nc;
3764:   }
3765:   PetscMalloc1(size, &perm);
3766:   for (f = 0; f < Nf; ++f) {
3767:     switch (dim) {
3768:     case 1:
3769:       PetscSectionGetFieldDof(section, eStart, f, &k);
3770:       PetscSectionGetFieldComponents(section, f, &Nc);
3771:       k = k/Nc + 1;
3772:       /*
3773:         Original ordering is [ edge of length k-1; vtx0; vtx1 ]
3774:         We want              [ vtx0; edge of length k-1; vtx1 ]
3775:       */
3776:       for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
3777:       for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
3778:       for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
3779:       foffset = offset;
3780:       break;
3781:     case 2:
3782:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3783:       PetscSectionGetFieldDof(section, eStart, f, &k);
3784:       PetscSectionGetFieldComponents(section, f, &Nc);
3785:       k = k/Nc + 1;
3786:       /* The SEM order is

3788:          v_lb, {e_b}, v_rb,
3789:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3790:          v_lt, reverse {e_t}, v_rt
3791:       */
3792:       {
3793:         const PetscInt of   = 0;
3794:         const PetscInt oeb  = of   + PetscSqr(k-1);
3795:         const PetscInt oer  = oeb  + (k-1);
3796:         const PetscInt oet  = oer  + (k-1);
3797:         const PetscInt oel  = oet  + (k-1);
3798:         const PetscInt ovlb = oel  + (k-1);
3799:         const PetscInt ovrb = ovlb + 1;
3800:         const PetscInt ovrt = ovrb + 1;
3801:         const PetscInt ovlt = ovrt + 1;
3802:         PetscInt       o;

3804:         /* bottom */
3805:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3806:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3807:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3808:         /* middle */
3809:         for (i = 0; i < k-1; ++i) {
3810:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3811:           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;
3812:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3813:         }
3814:         /* top */
3815:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3816:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3817:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3818:         foffset = offset;
3819:       }
3820:       break;
3821:     case 3:
3822:       /* The original hex closure is

3824:          {c,
3825:           f_b, f_t, f_f, f_b, f_r, f_l,
3826:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3827:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3828:       */
3829:       PetscSectionGetFieldDof(section, eStart, f, &k);
3830:       PetscSectionGetFieldComponents(section, f, &Nc);
3831:       k = k/Nc + 1;
3832:       /* The SEM order is
3833:          Bottom Slice
3834:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3835:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3836:          v_blb, {e_bb}, v_brb,

3838:          Middle Slice (j)
3839:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3840:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3841:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3843:          Top Slice
3844:          v_tlf, {e_tf}, v_trf,
3845:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3846:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3847:       */
3848:       {
3849:         const PetscInt oc    = 0;
3850:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3851:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3852:         const PetscInt off   = oft   + PetscSqr(k-1);
3853:         const PetscInt ofk   = off   + PetscSqr(k-1);
3854:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3855:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3856:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3857:         const PetscInt oebb  = oebl  + (k-1);
3858:         const PetscInt oebr  = oebb  + (k-1);
3859:         const PetscInt oebf  = oebr  + (k-1);
3860:         const PetscInt oetf  = oebf  + (k-1);
3861:         const PetscInt oetr  = oetf  + (k-1);
3862:         const PetscInt oetb  = oetr  + (k-1);
3863:         const PetscInt oetl  = oetb  + (k-1);
3864:         const PetscInt oerf  = oetl  + (k-1);
3865:         const PetscInt oelf  = oerf  + (k-1);
3866:         const PetscInt oelb  = oelf  + (k-1);
3867:         const PetscInt oerb  = oelb  + (k-1);
3868:         const PetscInt ovblf = oerb  + (k-1);
3869:         const PetscInt ovblb = ovblf + 1;
3870:         const PetscInt ovbrb = ovblb + 1;
3871:         const PetscInt ovbrf = ovbrb + 1;
3872:         const PetscInt ovtlf = ovbrf + 1;
3873:         const PetscInt ovtrf = ovtlf + 1;
3874:         const PetscInt ovtrb = ovtrf + 1;
3875:         const PetscInt ovtlb = ovtrb + 1;
3876:         PetscInt       o, n;

3878:         /* Bottom Slice */
3879:         /*   bottom */
3880:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3881:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3882:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3883:         /*   middle */
3884:         for (i = 0; i < k-1; ++i) {
3885:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3886:           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;}
3887:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3888:         }
3889:         /*   top */
3890:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3891:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3892:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3894:         /* Middle Slice */
3895:         for (j = 0; j < k-1; ++j) {
3896:           /*   bottom */
3897:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3898:           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;
3899:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3900:           /*   middle */
3901:           for (i = 0; i < k-1; ++i) {
3902:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3903:             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;
3904:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3905:           }
3906:           /*   top */
3907:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3908:           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;
3909:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3910:         }

3912:         /* Top Slice */
3913:         /*   bottom */
3914:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3915:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3916:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3917:         /*   middle */
3918:         for (i = 0; i < k-1; ++i) {
3919:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3920:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3921:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3922:         }
3923:         /*   top */
3924:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3925:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3926:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3928:         foffset = offset;
3929:       }
3930:       break;
3931:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3932:     }
3933:   }
3934:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3935:   /* Check permutation */
3936:   {
3937:     PetscInt *check;

3939:     PetscMalloc1(size, &check);
3940:     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]);}
3941:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3942:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3943:     PetscFree(check);
3944:   }
3945:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3946:   return(0);
3947: }

3949: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3950: {
3951:   PetscDS        prob;
3952:   PetscInt       depth, Nf, h;
3953:   DMLabel        label;

3957:   DMGetDS(dm, &prob);
3958:   Nf      = prob->Nf;
3959:   label   = dm->depthLabel;
3960:   *dspace = NULL;
3961:   if (field < Nf) {
3962:     PetscObject disc = prob->disc[field];

3964:     if (disc->classid == PETSCFE_CLASSID) {
3965:       PetscDualSpace dsp;

3967:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3968:       DMLabelGetNumValues(label,&depth);
3969:       DMLabelGetValue(label,point,&h);
3970:       h    = depth - 1 - h;
3971:       if (h) {
3972:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3973:       } else {
3974:         *dspace = dsp;
3975:       }
3976:     }
3977:   }
3978:   return(0);
3979: }


3982: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3983: {
3984:   PetscScalar    *array, *vArray;
3985:   const PetscInt *cone, *coneO;
3986:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3987:   PetscErrorCode  ierr;

3990:   PetscSectionGetChart(section, &pStart, &pEnd);
3991:   DMPlexGetConeSize(dm, point, &numPoints);
3992:   DMPlexGetCone(dm, point, &cone);
3993:   DMPlexGetConeOrientation(dm, point, &coneO);
3994:   if (!values || !*values) {
3995:     if ((point >= pStart) && (point < pEnd)) {
3996:       PetscInt dof;

3998:       PetscSectionGetDof(section, point, &dof);
3999:       size += dof;
4000:     }
4001:     for (p = 0; p < numPoints; ++p) {
4002:       const PetscInt cp = cone[p];
4003:       PetscInt       dof;

4005:       if ((cp < pStart) || (cp >= pEnd)) continue;
4006:       PetscSectionGetDof(section, cp, &dof);
4007:       size += dof;
4008:     }
4009:     if (!values) {
4010:       if (csize) *csize = size;
4011:       return(0);
4012:     }
4013:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
4014:   } else {
4015:     array = *values;
4016:   }
4017:   size = 0;
4018:   VecGetArray(v, &vArray);
4019:   if ((point >= pStart) && (point < pEnd)) {
4020:     PetscInt     dof, off, d;
4021:     PetscScalar *varr;

4023:     PetscSectionGetDof(section, point, &dof);
4024:     PetscSectionGetOffset(section, point, &off);
4025:     varr = &vArray[off];
4026:     for (d = 0; d < dof; ++d, ++offset) {
4027:       array[offset] = varr[d];
4028:     }
4029:     size += dof;
4030:   }
4031:   for (p = 0; p < numPoints; ++p) {
4032:     const PetscInt cp = cone[p];
4033:     PetscInt       o  = coneO[p];
4034:     PetscInt       dof, off, d;
4035:     PetscScalar   *varr;

4037:     if ((cp < pStart) || (cp >= pEnd)) continue;
4038:     PetscSectionGetDof(section, cp, &dof);
4039:     PetscSectionGetOffset(section, cp, &off);
4040:     varr = &vArray[off];
4041:     if (o >= 0) {
4042:       for (d = 0; d < dof; ++d, ++offset) {
4043:         array[offset] = varr[d];
4044:       }
4045:     } else {
4046:       for (d = dof-1; d >= 0; --d, ++offset) {
4047:         array[offset] = varr[d];
4048:       }
4049:     }
4050:     size += dof;
4051:   }
4052:   VecRestoreArray(v, &vArray);
4053:   if (!*values) {
4054:     if (csize) *csize = size;
4055:     *values = array;
4056:   } else {
4057:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4058:     *csize = size;
4059:   }
4060:   return(0);
4061: }

4063: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4064: {
4065:   const PetscInt *cla;
4066:   PetscInt       np, *pts = NULL;

4070:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
4071:   if (!*clPoints) {
4072:     PetscInt pStart, pEnd, p, q;

4074:     PetscSectionGetChart(section, &pStart, &pEnd);
4075:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
4076:     /* Compress out points not in the section */
4077:     for (p = 0, q = 0; p < np; p++) {
4078:       PetscInt r = pts[2*p];
4079:       if ((r >= pStart) && (r < pEnd)) {
4080:         pts[q*2]   = r;
4081:         pts[q*2+1] = pts[2*p+1];
4082:         ++q;
4083:       }
4084:     }
4085:     np = q;
4086:     cla = NULL;
4087:   } else {
4088:     PetscInt dof, off;

4090:     PetscSectionGetDof(*clSec, point, &dof);
4091:     PetscSectionGetOffset(*clSec, point, &off);
4092:     ISGetIndices(*clPoints, &cla);
4093:     np   = dof/2;
4094:     pts  = (PetscInt *) &cla[off];
4095:   }
4096:   *numPoints = np;
4097:   *points    = pts;
4098:   *clp       = cla;

4100:   return(0);
4101: }

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

4108:   if (!*clPoints) {
4109:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
4110:   } else {
4111:     ISRestoreIndices(*clPoints, clp);
4112:   }
4113:   *numPoints = 0;
4114:   *points    = NULL;
4115:   *clSec     = NULL;
4116:   *clPoints  = NULL;
4117:   *clp       = NULL;
4118:   return(0);
4119: }

4121: 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[])
4122: {
4123:   PetscInt          offset = 0, p;
4124:   const PetscInt    **perms = NULL;
4125:   const PetscScalar **flips = NULL;
4126:   PetscErrorCode    ierr;

4129:   *size = 0;
4130:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4131:   for (p = 0; p < numPoints; p++) {
4132:     const PetscInt    point = points[2*p];
4133:     const PetscInt    *perm = perms ? perms[p] : NULL;
4134:     const PetscScalar *flip = flips ? flips[p] : NULL;
4135:     PetscInt          dof, off, d;
4136:     const PetscScalar *varr;

4138:     PetscSectionGetDof(section, point, &dof);
4139:     PetscSectionGetOffset(section, point, &off);
4140:     varr = &vArray[off];
4141:     if (clperm) {
4142:       if (perm) {
4143:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4144:       } else {
4145:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4146:       }
4147:       if (flip) {
4148:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4149:       }
4150:     } else {
4151:       if (perm) {
4152:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4153:       } else {
4154:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4155:       }
4156:       if (flip) {
4157:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4158:       }
4159:     }
4160:     offset += dof;
4161:   }
4162:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4163:   *size = offset;
4164:   return(0);
4165: }

4167: 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[])
4168: {
4169:   PetscInt          offset = 0, f;
4170:   PetscErrorCode    ierr;

4173:   *size = 0;
4174:   for (f = 0; f < numFields; ++f) {
4175:     PetscInt          p;
4176:     const PetscInt    **perms = NULL;
4177:     const PetscScalar **flips = NULL;

4179:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4180:     for (p = 0; p < numPoints; p++) {
4181:       const PetscInt    point = points[2*p];
4182:       PetscInt          fdof, foff, b;
4183:       const PetscScalar *varr;
4184:       const PetscInt    *perm = perms ? perms[p] : NULL;
4185:       const PetscScalar *flip = flips ? flips[p] : NULL;

4187:       PetscSectionGetFieldDof(section, point, f, &fdof);
4188:       PetscSectionGetFieldOffset(section, point, f, &foff);
4189:       varr = &vArray[foff];
4190:       if (clperm) {
4191:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4192:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4193:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4194:       } else {
4195:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4196:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4197:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4198:       }
4199:       offset += fdof;
4200:     }
4201:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4202:   }
4203:   *size = offset;
4204:   return(0);
4205: }

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

4210:   Not collective

4212:   Input Parameters:
4213: + dm - The DM
4214: . section - The section describing the layout in v, or NULL to use the default section
4215: . v - The local vector
4216: . point - The point in the DM
4217: . csize - The size of the input values array, or NULL
4218: - values - An array to use for the values, or NULL to have it allocated automatically

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

4224: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4225: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4226: $ assembly function, and a user may already have allocated storage for this operation.
4227: $
4228: $ A typical use could be
4229: $
4230: $  values = NULL;
4231: $  DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4232: $  for (cl = 0; cl < clSize; ++cl) {
4233: $    <Compute on closure>
4234: $  }
4235: $  DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4236: $
4237: $ or
4238: $
4239: $  PetscMalloc1(clMaxSize, &values);
4240: $  for (p = pStart; p < pEnd; ++p) {
4241: $    clSize = clMaxSize;
4242: $    DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4243: $    for (cl = 0; cl < clSize; ++cl) {
4244: $      <Compute on closure>
4245: $    }
4246: $  }
4247: $  PetscFree(values);

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

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

4255:   Level: intermediate

4257: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4258: @*/
4259: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4260: {
4261:   PetscSection       clSection;
4262:   IS                 clPoints;
4263:   PetscScalar       *array;
4264:   const PetscScalar *vArray;
4265:   PetscInt          *points = NULL;
4266:   const PetscInt    *clp, *perm;
4267:   PetscInt           depth, numFields, numPoints, size;
4268:   PetscErrorCode     ierr;

4272:   if (!section) {DMGetSection(dm, &section);}
4275:   DMPlexGetDepth(dm, &depth);
4276:   PetscSectionGetNumFields(section, &numFields);
4277:   if (depth == 1 && numFields < 2) {
4278:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4279:     return(0);
4280:   }
4281:   /* Get points */
4282:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4283:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4284:   /* Get array */
4285:   if (!values || !*values) {
4286:     PetscInt asize = 0, dof, p;

4288:     for (p = 0; p < numPoints*2; p += 2) {
4289:       PetscSectionGetDof(section, points[p], &dof);
4290:       asize += dof;
4291:     }
4292:     if (!values) {
4293:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4294:       if (csize) *csize = asize;
4295:       return(0);
4296:     }
4297:     DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4298:   } else {
4299:     array = *values;
4300:   }
4301:   VecGetArrayRead(v, &vArray);
4302:   /* Get values */
4303:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4304:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4305:   /* Cleanup points */
4306:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4307:   /* Cleanup array */
4308:   VecRestoreArrayRead(v, &vArray);
4309:   if (!*values) {
4310:     if (csize) *csize = size;
4311:     *values = array;
4312:   } else {
4313:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4314:     *csize = size;
4315:   }
4316:   return(0);
4317: }

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

4322:   Not collective

4324:   Input Parameters:
4325: + dm - The DM
4326: . section - The section describing the layout in v, or NULL to use the default section
4327: . v - The local vector
4328: . point - The point in the DM
4329: . csize - The number of values in the closure, or NULL
4330: - values - The array of values, which is a borrowed array and should not be freed

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

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

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

4340:   Level: intermediate

4342: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4343: @*/
4344: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4345: {
4346:   PetscInt       size = 0;

4350:   /* Should work without recalculating size */
4351:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4352:   *values = NULL;
4353:   return(0);
4354: }

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

4359: 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[])
4360: {
4361:   PetscInt        cdof;   /* The number of constraints on this point */
4362:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4363:   PetscScalar    *a;
4364:   PetscInt        off, cind = 0, k;
4365:   PetscErrorCode  ierr;

4368:   PetscSectionGetConstraintDof(section, point, &cdof);
4369:   PetscSectionGetOffset(section, point, &off);
4370:   a    = &array[off];
4371:   if (!cdof || setBC) {
4372:     if (clperm) {
4373:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4374:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4375:     } else {
4376:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4377:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4378:     }
4379:   } else {
4380:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4381:     if (clperm) {
4382:       if (perm) {for (k = 0; k < dof; ++k) {
4383:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4384:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4385:         }
4386:       } else {
4387:         for (k = 0; k < dof; ++k) {
4388:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4389:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4390:         }
4391:       }
4392:     } else {
4393:       if (perm) {
4394:         for (k = 0; k < dof; ++k) {
4395:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4396:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4397:         }
4398:       } else {
4399:         for (k = 0; k < dof; ++k) {
4400:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4401:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4402:         }
4403:       }
4404:     }
4405:   }
4406:   return(0);
4407: }

4409: 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[])
4410: {
4411:   PetscInt        cdof;   /* The number of constraints on this point */
4412:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4413:   PetscScalar    *a;
4414:   PetscInt        off, cind = 0, k;
4415:   PetscErrorCode  ierr;

4418:   PetscSectionGetConstraintDof(section, point, &cdof);
4419:   PetscSectionGetOffset(section, point, &off);
4420:   a    = &array[off];
4421:   if (cdof) {
4422:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4423:     if (clperm) {
4424:       if (perm) {
4425:         for (k = 0; k < dof; ++k) {
4426:           if ((cind < cdof) && (k == cdofs[cind])) {
4427:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4428:             cind++;
4429:           }
4430:         }
4431:       } else {
4432:         for (k = 0; k < dof; ++k) {
4433:           if ((cind < cdof) && (k == cdofs[cind])) {
4434:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4435:             cind++;
4436:           }
4437:         }
4438:       }
4439:     } else {
4440:       if (perm) {
4441:         for (k = 0; k < dof; ++k) {
4442:           if ((cind < cdof) && (k == cdofs[cind])) {
4443:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4444:             cind++;
4445:           }
4446:         }
4447:       } else {
4448:         for (k = 0; k < dof; ++k) {
4449:           if ((cind < cdof) && (k == cdofs[cind])) {
4450:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4451:             cind++;
4452:           }
4453:         }
4454:       }
4455:     }
4456:   }
4457:   return(0);
4458: }

4460: 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[])
4461: {
4462:   PetscScalar    *a;
4463:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4464:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4465:   PetscInt        cind = 0, b;
4466:   PetscErrorCode  ierr;

4469:   PetscSectionGetFieldDof(section, point, f, &fdof);
4470:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4471:   PetscSectionGetFieldOffset(section, point, f, &foff);
4472:   a    = &array[foff];
4473:   if (!fcdof || setBC) {
4474:     if (clperm) {
4475:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4476:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4477:     } else {
4478:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4479:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4480:     }
4481:   } else {
4482:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4483:     if (clperm) {
4484:       if (perm) {
4485:         for (b = 0; b < fdof; b++) {
4486:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4487:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4488:         }
4489:       } else {
4490:         for (b = 0; b < fdof; b++) {
4491:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4492:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4493:         }
4494:       }
4495:     } else {
4496:       if (perm) {
4497:         for (b = 0; b < fdof; b++) {
4498:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4499:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4500:         }
4501:       } else {
4502:         for (b = 0; b < fdof; b++) {
4503:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4504:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4505:         }
4506:       }
4507:     }
4508:   }
4509:   *offset += fdof;
4510:   return(0);
4511: }

4513: 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[])
4514: {
4515:   PetscScalar    *a;
4516:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4517:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4518:   PetscInt        cind = 0, ncind = 0, b;
4519:   PetscBool       ncSet, fcSet;
4520:   PetscErrorCode  ierr;

4523:   PetscSectionGetFieldDof(section, point, f, &fdof);
4524:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4525:   PetscSectionGetFieldOffset(section, point, f, &foff);
4526:   a    = &array[foff];
4527:   if (fcdof) {
4528:     /* We just override fcdof and fcdofs with Ncc and comps */
4529:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4530:     if (clperm) {
4531:       if (perm) {
4532:         if (comps) {
4533:           for (b = 0; b < fdof; b++) {
4534:             ncSet = fcSet = PETSC_FALSE;
4535:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4536:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4537:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4538:           }
4539:         } else {
4540:           for (b = 0; b < fdof; b++) {
4541:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4542:               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4543:               ++cind;
4544:             }
4545:           }
4546:         }
4547:       } else {
4548:         if (comps) {
4549:           for (b = 0; b < fdof; b++) {
4550:             ncSet = fcSet = PETSC_FALSE;
4551:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4552:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4553:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4554:           }
4555:         } else {
4556:           for (b = 0; b < fdof; b++) {
4557:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4558:               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4559:               ++cind;
4560:             }
4561:           }
4562:         }
4563:       }
4564:     } else {
4565:       if (perm) {
4566:         if (comps) {
4567:           for (b = 0; b < fdof; b++) {
4568:             ncSet = fcSet = PETSC_FALSE;
4569:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4570:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4571:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4572:           }
4573:         } else {
4574:           for (b = 0; b < fdof; b++) {
4575:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4576:               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4577:               ++cind;
4578:             }
4579:           }
4580:         }
4581:       } else {
4582:         if (comps) {
4583:           for (b = 0; b < fdof; b++) {
4584:             ncSet = fcSet = PETSC_FALSE;
4585:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4586:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4587:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4588:           }
4589:         } else {
4590:           for (b = 0; b < fdof; b++) {
4591:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4592:               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4593:               ++cind;
4594:             }
4595:           }
4596:         }
4597:       }
4598:     }
4599:   }
4600:   *offset += fdof;
4601:   return(0);
4602: }

4604: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4605: {
4606:   PetscScalar    *array;
4607:   const PetscInt *cone, *coneO;
4608:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4609:   PetscErrorCode  ierr;

4612:   PetscSectionGetChart(section, &pStart, &pEnd);
4613:   DMPlexGetConeSize(dm, point, &numPoints);
4614:   DMPlexGetCone(dm, point, &cone);
4615:   DMPlexGetConeOrientation(dm, point, &coneO);
4616:   VecGetArray(v, &array);
4617:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4618:     const PetscInt cp = !p ? point : cone[p-1];
4619:     const PetscInt o  = !p ? 0     : coneO[p-1];

4621:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4622:     PetscSectionGetDof(section, cp, &dof);
4623:     /* ADD_VALUES */
4624:     {
4625:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4626:       PetscScalar    *a;
4627:       PetscInt        cdof, coff, cind = 0, k;

4629:       PetscSectionGetConstraintDof(section, cp, &cdof);
4630:       PetscSectionGetOffset(section, cp, &coff);
4631:       a    = &array[coff];
4632:       if (!cdof) {
4633:         if (o >= 0) {
4634:           for (k = 0; k < dof; ++k) {
4635:             a[k] += values[off+k];
4636:           }
4637:         } else {
4638:           for (k = 0; k < dof; ++k) {
4639:             a[k] += values[off+dof-k-1];
4640:           }
4641:         }
4642:       } else {
4643:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4644:         if (o >= 0) {
4645:           for (k = 0; k < dof; ++k) {
4646:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4647:             a[k] += values[off+k];
4648:           }
4649:         } else {
4650:           for (k = 0; k < dof; ++k) {
4651:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4652:             a[k] += values[off+dof-k-1];
4653:           }
4654:         }
4655:       }
4656:     }
4657:   }
4658:   VecRestoreArray(v, &array);
4659:   return(0);
4660: }

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

4665:   Not collective

4667:   Input Parameters:
4668: + dm - The DM
4669: . section - The section describing the layout in v, or NULL to use the default section
4670: . v - The local vector
4671: . point - The point in the DM
4672: . values - The array of values
4673: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4674:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

4679:   Level: intermediate

4681: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4682: @*/
4683: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4684: {
4685:   PetscSection    clSection;
4686:   IS              clPoints;
4687:   PetscScalar    *array;
4688:   PetscInt       *points = NULL;
4689:   const PetscInt *clp, *clperm;
4690:   PetscInt        depth, numFields, numPoints, p;
4691:   PetscErrorCode  ierr;

4695:   if (!section) {DMGetSection(dm, &section);}
4698:   DMPlexGetDepth(dm, &depth);
4699:   PetscSectionGetNumFields(section, &numFields);
4700:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4701:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4702:     return(0);
4703:   }
4704:   /* Get points */
4705:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4706:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4707:   /* Get array */
4708:   VecGetArray(v, &array);
4709:   /* Get values */
4710:   if (numFields > 0) {
4711:     PetscInt offset = 0, f;
4712:     for (f = 0; f < numFields; ++f) {
4713:       const PetscInt    **perms = NULL;
4714:       const PetscScalar **flips = NULL;

4716:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4717:       switch (mode) {
4718:       case INSERT_VALUES:
4719:         for (p = 0; p < numPoints; p++) {
4720:           const PetscInt    point = points[2*p];
4721:           const PetscInt    *perm = perms ? perms[p] : NULL;
4722:           const PetscScalar *flip = flips ? flips[p] : NULL;
4723:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4724:         } break;
4725:       case INSERT_ALL_VALUES:
4726:         for (p = 0; p < numPoints; p++) {
4727:           const PetscInt    point = points[2*p];
4728:           const PetscInt    *perm = perms ? perms[p] : NULL;
4729:           const PetscScalar *flip = flips ? flips[p] : NULL;
4730:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4731:         } break;
4732:       case INSERT_BC_VALUES:
4733:         for (p = 0; p < numPoints; p++) {
4734:           const PetscInt    point = points[2*p];
4735:           const PetscInt    *perm = perms ? perms[p] : NULL;
4736:           const PetscScalar *flip = flips ? flips[p] : NULL;
4737:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4738:         } break;
4739:       case ADD_VALUES:
4740:         for (p = 0; p < numPoints; p++) {
4741:           const PetscInt    point = points[2*p];
4742:           const PetscInt    *perm = perms ? perms[p] : NULL;
4743:           const PetscScalar *flip = flips ? flips[p] : NULL;
4744:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4745:         } break;
4746:       case ADD_ALL_VALUES:
4747:         for (p = 0; p < numPoints; p++) {
4748:           const PetscInt    point = points[2*p];
4749:           const PetscInt    *perm = perms ? perms[p] : NULL;
4750:           const PetscScalar *flip = flips ? flips[p] : NULL;
4751:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4752:         } break;
4753:       case ADD_BC_VALUES:
4754:         for (p = 0; p < numPoints; p++) {
4755:           const PetscInt    point = points[2*p];
4756:           const PetscInt    *perm = perms ? perms[p] : NULL;
4757:           const PetscScalar *flip = flips ? flips[p] : NULL;
4758:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4759:         } break;
4760:       default:
4761:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4762:       }
4763:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4764:     }
4765:   } else {
4766:     PetscInt dof, off;
4767:     const PetscInt    **perms = NULL;
4768:     const PetscScalar **flips = NULL;

4770:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4771:     switch (mode) {
4772:     case INSERT_VALUES:
4773:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4774:         const PetscInt    point = points[2*p];
4775:         const PetscInt    *perm = perms ? perms[p] : NULL;
4776:         const PetscScalar *flip = flips ? flips[p] : NULL;
4777:         PetscSectionGetDof(section, point, &dof);
4778:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4779:       } break;
4780:     case INSERT_ALL_VALUES:
4781:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4782:         const PetscInt    point = points[2*p];
4783:         const PetscInt    *perm = perms ? perms[p] : NULL;
4784:         const PetscScalar *flip = flips ? flips[p] : NULL;
4785:         PetscSectionGetDof(section, point, &dof);
4786:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4787:       } break;
4788:     case INSERT_BC_VALUES:
4789:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4790:         const PetscInt    point = points[2*p];
4791:         const PetscInt    *perm = perms ? perms[p] : NULL;
4792:         const PetscScalar *flip = flips ? flips[p] : NULL;
4793:         PetscSectionGetDof(section, point, &dof);
4794:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4795:       } break;
4796:     case ADD_VALUES:
4797:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4798:         const PetscInt    point = points[2*p];
4799:         const PetscInt    *perm = perms ? perms[p] : NULL;
4800:         const PetscScalar *flip = flips ? flips[p] : NULL;
4801:         PetscSectionGetDof(section, point, &dof);
4802:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4803:       } break;
4804:     case ADD_ALL_VALUES:
4805:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4806:         const PetscInt    point = points[2*p];
4807:         const PetscInt    *perm = perms ? perms[p] : NULL;
4808:         const PetscScalar *flip = flips ? flips[p] : NULL;
4809:         PetscSectionGetDof(section, point, &dof);
4810:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4811:       } break;
4812:     case ADD_BC_VALUES:
4813:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4814:         const PetscInt    point = points[2*p];
4815:         const PetscInt    *perm = perms ? perms[p] : NULL;
4816:         const PetscScalar *flip = flips ? flips[p] : NULL;
4817:         PetscSectionGetDof(section, point, &dof);
4818:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4819:       } break;
4820:     default:
4821:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4822:     }
4823:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4824:   }
4825:   /* Cleanup points */
4826:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4827:   /* Cleanup array */
4828:   VecRestoreArray(v, &array);
4829:   return(0);
4830: }

4832: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4833: {
4834:   PetscSection      clSection;
4835:   IS                clPoints;
4836:   PetscScalar       *array;
4837:   PetscInt          *points = NULL;
4838:   const PetscInt    *clp, *clperm;
4839:   PetscInt          numFields, numPoints, p;
4840:   PetscInt          offset = 0, f;
4841:   PetscErrorCode    ierr;

4845:   if (!section) {DMGetSection(dm, &section);}
4848:   PetscSectionGetNumFields(section, &numFields);
4849:   /* Get points */
4850:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4851:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4852:   /* Get array */
4853:   VecGetArray(v, &array);
4854:   /* Get values */
4855:   for (f = 0; f < numFields; ++f) {
4856:     const PetscInt    **perms = NULL;
4857:     const PetscScalar **flips = NULL;

4859:     if (!fieldActive[f]) {
4860:       for (p = 0; p < numPoints*2; p += 2) {
4861:         PetscInt fdof;
4862:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4863:         offset += fdof;
4864:       }
4865:       continue;
4866:     }
4867:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4868:     switch (mode) {
4869:     case INSERT_VALUES:
4870:       for (p = 0; p < numPoints; p++) {
4871:         const PetscInt    point = points[2*p];
4872:         const PetscInt    *perm = perms ? perms[p] : NULL;
4873:         const PetscScalar *flip = flips ? flips[p] : NULL;
4874:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4875:       } break;
4876:     case INSERT_ALL_VALUES:
4877:       for (p = 0; p < numPoints; p++) {
4878:         const PetscInt    point = points[2*p];
4879:         const PetscInt    *perm = perms ? perms[p] : NULL;
4880:         const PetscScalar *flip = flips ? flips[p] : NULL;
4881:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4882:         } break;
4883:     case INSERT_BC_VALUES:
4884:       for (p = 0; p < numPoints; p++) {
4885:         const PetscInt    point = points[2*p];
4886:         const PetscInt    *perm = perms ? perms[p] : NULL;
4887:         const PetscScalar *flip = flips ? flips[p] : NULL;
4888:         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4889:       } break;
4890:     case ADD_VALUES:
4891:       for (p = 0; p < numPoints; p++) {
4892:         const PetscInt    point = points[2*p];
4893:         const PetscInt    *perm = perms ? perms[p] : NULL;
4894:         const PetscScalar *flip = flips ? flips[p] : NULL;
4895:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4896:       } break;
4897:     case ADD_ALL_VALUES:
4898:       for (p = 0; p < numPoints; p++) {
4899:         const PetscInt    point = points[2*p];
4900:         const PetscInt    *perm = perms ? perms[p] : NULL;
4901:         const PetscScalar *flip = flips ? flips[p] : NULL;
4902:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4903:       } break;
4904:     default:
4905:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4906:     }
4907:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4908:   }
4909:   /* Cleanup points */
4910:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4911:   /* Cleanup array */
4912:   VecRestoreArray(v, &array);
4913:   return(0);
4914: }

4916: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4917: {
4918:   PetscMPIInt    rank;
4919:   PetscInt       i, j;

4923:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4924:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4925:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4926:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4927:   numCIndices = numCIndices ? numCIndices : numRIndices;
4928:   for (i = 0; i < numRIndices; i++) {
4929:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4930:     for (j = 0; j < numCIndices; j++) {
4931: #if defined(PETSC_USE_COMPLEX)
4932:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4933: #else
4934:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4935: #endif
4936:     }
4937:     PetscViewerASCIIPrintf(viewer, "\n");
4938:   }
4939:   return(0);
4940: }

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

4945:   Input Parameters:
4946: + section - The section for this data layout
4947: . point   - The point contributing dofs with these indices
4948: . off     - The global offset of this point
4949: . loff    - The local offset of each field
4950: . setBC   - The flag determining whether to include indices of bounsary values
4951: . perm    - A permutation of the dofs on this point, or NULL
4952: - indperm - A permutation of the entire indices array, or NULL

4954:   Output Parameter:
4955: . indices - Indices for dofs on this point

4957:   Level: developer

4959:   Note: The indices could be local or global, depending on the value of 'off'.
4960: */
4961: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
4962: {
4963:   PetscInt        dof;   /* The number of unknowns on this point */
4964:   PetscInt        cdof;  /* The number of constraints on this point */
4965:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4966:   PetscInt        cind = 0, k;
4967:   PetscErrorCode  ierr;

4970:   PetscSectionGetDof(section, point, &dof);
4971:   PetscSectionGetConstraintDof(section, point, &cdof);
4972:   if (!cdof || setBC) {
4973:     for (k = 0; k < dof; ++k) {
4974:       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
4975:       const PetscInt ind    = indperm ? indperm[preind] : preind;

4977:       indices[ind] = off + k;
4978:     }
4979:   } else {
4980:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4981:     for (k = 0; k < dof; ++k) {
4982:       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
4983:       const PetscInt ind    = indperm ? indperm[preind] : preind;

4985:       if ((cind < cdof) && (k == cdofs[cind])) {
4986:         /* Insert check for returning constrained indices */
4987:         indices[ind] = -(off+k+1);
4988:         ++cind;
4989:       } else {
4990:         indices[ind] = off+k-cind;
4991:       }
4992:     }
4993:   }
4994:   *loff += dof;
4995:   return(0);
4996: }

4998: /*
4999:   This version only believes the point offset from the globalSection

5001:  . off - The global offset of this point
5002: */
5003: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5004: {
5005:   PetscInt       numFields, foff, f;

5009:   PetscSectionGetNumFields(section, &numFields);
5010:   for (f = 0, foff = 0; f < numFields; ++f) {
5011:     PetscInt        fdof, cfdof;
5012:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5013:     PetscInt        cind = 0, b;
5014:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5016:     PetscSectionGetFieldDof(section, point, f, &fdof);
5017:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5018:     if (!cfdof || setBC) {
5019:       for (b = 0; b < fdof; ++b) {
5020:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5021:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5023:         indices[ind] = off+foff+b;
5024:       }
5025:     } else {
5026:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5027:       for (b = 0; b < fdof; ++b) {
5028:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5029:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5031:         if ((cind < cfdof) && (b == fcdofs[cind])) {
5032:           indices[ind] = -(off+foff+b+1);
5033:           ++cind;
5034:         } else {
5035:           indices[ind] = off+foff+b-cind;
5036:         }
5037:       }
5038:     }
5039:     foff     += (setBC ? fdof : (fdof - cfdof));
5040:     foffs[f] += fdof;
5041:   }
5042:   return(0);
5043: }

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

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

5056:   PetscSectionGetNumFields(section, &numFields);
5057:   for (f = 0; f < numFields; ++f) {
5058:     PetscInt        fdof, cfdof;
5059:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5060:     PetscInt        cind = 0, b;
5061:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5063:     PetscSectionGetFieldDof(section, point, f, &fdof);
5064:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5065:     PetscSectionGetFieldOffset(globalSection, point, f, &foff);
5066:     if (!cfdof || setBC) {
5067:       for (b = 0; b < fdof; ++b) {
5068:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5069:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5071:         indices[ind] = foff+b;
5072:       }
5073:     } else {
5074:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5075:       for (b = 0; b < fdof; ++b) {
5076:         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5077:         const PetscInt ind    = indperm ? indperm[preind] : preind;

5079:         if ((cind < cfdof) && (b == fcdofs[cind])) {
5080:           indices[ind] = -(foff+b+1);
5081:           ++cind;
5082:         } else {
5083:           indices[ind] = foff+b-cind;
5084:         }
5085:       }
5086:     }
5087:     foffs[f] += fdof;
5088:   }
5089:   return(0);
5090: }

5092: 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)
5093: {
5094:   Mat             cMat;
5095:   PetscSection    aSec, cSec;
5096:   IS              aIS;
5097:   PetscInt        aStart = -1, aEnd = -1;
5098:   const PetscInt  *anchors;
5099:   PetscInt        numFields, f, p, q, newP = 0;
5100:   PetscInt        newNumPoints = 0, newNumIndices = 0;
5101:   PetscInt        *newPoints, *indices, *newIndices;
5102:   PetscInt        maxAnchor, maxDof;
5103:   PetscInt        newOffsets[32];
5104:   PetscInt        *pointMatOffsets[32];
5105:   PetscInt        *newPointOffsets[32];
5106:   PetscScalar     *pointMat[32];
5107:   PetscScalar     *newValues=NULL,*tmpValues;
5108:   PetscBool       anyConstrained = PETSC_FALSE;
5109:   PetscErrorCode  ierr;

5114:   PetscSectionGetNumFields(section, &numFields);

5116:   DMPlexGetAnchors(dm,&aSec,&aIS);
5117:   /* if there are point-to-point constraints */
5118:   if (aSec) {
5119:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
5120:     ISGetIndices(aIS,&anchors);
5121:     PetscSectionGetChart(aSec,&aStart,&aEnd);
5122:     /* figure out how many points are going to be in the new element matrix
5123:      * (we allow double counting, because it's all just going to be summed
5124:      * into the global matrix anyway) */
5125:     for (p = 0; p < 2*numPoints; p+=2) {
5126:       PetscInt b    = points[p];
5127:       PetscInt bDof = 0, bSecDof;

5129:       PetscSectionGetDof(section,b,&bSecDof);
5130:       if (!bSecDof) {
5131:         continue;
5132:       }
5133:       if (b >= aStart && b < aEnd) {
5134:         PetscSectionGetDof(aSec,b,&bDof);
5135:       }
5136:       if (bDof) {
5137:         /* this point is constrained */
5138:         /* it is going to be replaced by its anchors */
5139:         PetscInt bOff, q;

5141:         anyConstrained = PETSC_TRUE;
5142:         newNumPoints  += bDof;
5143:         PetscSectionGetOffset(aSec,b,&bOff);
5144:         for (q = 0; q < bDof; q++) {
5145:           PetscInt a = anchors[bOff + q];
5146:           PetscInt aDof;

5148:           PetscSectionGetDof(section,a,&aDof);
5149:           newNumIndices += aDof;
5150:           for (f = 0; f < numFields; ++f) {
5151:             PetscInt fDof;

5153:             PetscSectionGetFieldDof(section, a, f, &fDof);
5154:             newOffsets[f+1] += fDof;
5155:           }
5156:         }
5157:       }
5158:       else {
5159:         /* this point is not constrained */
5160:         newNumPoints++;
5161:         newNumIndices += bSecDof;
5162:         for (f = 0; f < numFields; ++f) {
5163:           PetscInt fDof;

5165:           PetscSectionGetFieldDof(section, b, f, &fDof);
5166:           newOffsets[f+1] += fDof;
5167:         }
5168:       }
5169:     }
5170:   }
5171:   if (!anyConstrained) {
5172:     if (outNumPoints)  *outNumPoints  = 0;
5173:     if (outNumIndices) *outNumIndices = 0;
5174:     if (outPoints)     *outPoints     = NULL;
5175:     if (outValues)     *outValues     = NULL;
5176:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5177:     return(0);
5178:   }

5180:   if (outNumPoints)  *outNumPoints  = newNumPoints;
5181:   if (outNumIndices) *outNumIndices = newNumIndices;

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

5185:   if (!outPoints && !outValues) {
5186:     if (offsets) {
5187:       for (f = 0; f <= numFields; f++) {
5188:         offsets[f] = newOffsets[f];
5189:       }
5190:     }
5191:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5192:     return(0);
5193:   }

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

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

5199:   /* workspaces */
5200:   if (numFields) {
5201:     for (f = 0; f < numFields; f++) {
5202:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5203:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5204:     }
5205:   }
5206:   else {
5207:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5208:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5209:   }

5211:   /* get workspaces for the point-to-point matrices */
5212:   if (numFields) {
5213:     PetscInt totalOffset, totalMatOffset;

5215:     for (p = 0; p < numPoints; p++) {
5216:       PetscInt b    = points[2*p];
5217:       PetscInt bDof = 0, bSecDof;

5219:       PetscSectionGetDof(section,b,&bSecDof);
5220:       if (!bSecDof) {
5221:         for (f = 0; f < numFields; f++) {
5222:           newPointOffsets[f][p + 1] = 0;
5223:           pointMatOffsets[f][p + 1] = 0;
5224:         }
5225:         continue;
5226:       }
5227:       if (b >= aStart && b < aEnd) {
5228:         PetscSectionGetDof(aSec, b, &bDof);
5229:       }
5230:       if (bDof) {
5231:         for (f = 0; f < numFields; f++) {
5232:           PetscInt fDof, q, bOff, allFDof = 0;

5234:           PetscSectionGetFieldDof(section, b, f, &fDof);
5235:           PetscSectionGetOffset(aSec, b, &bOff);
5236:           for (q = 0; q < bDof; q++) {
5237:             PetscInt a = anchors[bOff + q];
5238:             PetscInt aFDof;

5240:             PetscSectionGetFieldDof(section, a, f, &aFDof);
5241:             allFDof += aFDof;
5242:           }
5243:           newPointOffsets[f][p+1] = allFDof;
5244:           pointMatOffsets[f][p+1] = fDof * allFDof;
5245:         }
5246:       }
5247:       else {
5248:         for (f = 0; f < numFields; f++) {
5249:           PetscInt fDof;

5251:           PetscSectionGetFieldDof(section, b, f, &fDof);
5252:           newPointOffsets[f][p+1] = fDof;
5253:           pointMatOffsets[f][p+1] = 0;
5254:         }
5255:       }
5256:     }
5257:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5258:       newPointOffsets[f][0] = totalOffset;
5259:       pointMatOffsets[f][0] = totalMatOffset;
5260:       for (p = 0; p < numPoints; p++) {
5261:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5262:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5263:       }
5264:       totalOffset    = newPointOffsets[f][numPoints];
5265:       totalMatOffset = pointMatOffsets[f][numPoints];
5266:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5267:     }
5268:   }
5269:   else {
5270:     for (p = 0; p < numPoints; p++) {
5271:       PetscInt b    = points[2*p];
5272:       PetscInt bDof = 0, bSecDof;

5274:       PetscSectionGetDof(section,b,&bSecDof);
5275:       if (!bSecDof) {
5276:         newPointOffsets[0][p + 1] = 0;
5277:         pointMatOffsets[0][p + 1] = 0;
5278:         continue;
5279:       }
5280:       if (b >= aStart && b < aEnd) {
5281:         PetscSectionGetDof(aSec, b, &bDof);
5282:       }
5283:       if (bDof) {
5284:         PetscInt bOff, q, allDof = 0;

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

5290:           PetscSectionGetDof(section, a, &aDof);
5291:           allDof += aDof;
5292:         }
5293:         newPointOffsets[0][p+1] = allDof;
5294:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5295:       }
5296:       else {
5297:         newPointOffsets[0][p+1] = bSecDof;
5298:         pointMatOffsets[0][p+1] = 0;
5299:       }
5300:     }
5301:     newPointOffsets[0][0] = 0;
5302:     pointMatOffsets[0][0] = 0;
5303:     for (p = 0; p < numPoints; p++) {
5304:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5305:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5306:     }
5307:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5308:   }

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

5313:   /* get the point-to-point matrices; construct newPoints */
5314:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5315:   PetscSectionGetMaxDof(section, &maxDof);
5316:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5317:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5318:   if (numFields) {
5319:     for (p = 0, newP = 0; p < numPoints; p++) {
5320:       PetscInt b    = points[2*p];
5321:       PetscInt o    = points[2*p+1];
5322:       PetscInt bDof = 0, bSecDof;

5324:       PetscSectionGetDof(section, b, &bSecDof);
5325:       if (!bSecDof) {
5326:         continue;
5327:       }
5328:       if (b >= aStart && b < aEnd) {
5329:         PetscSectionGetDof(aSec, b, &bDof);
5330:       }
5331:       if (bDof) {
5332:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5334:         fStart[0] = 0;
5335:         fEnd[0]   = 0;
5336:         for (f = 0; f < numFields; f++) {
5337:           PetscInt fDof;

5339:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5340:           fStart[f+1] = fStart[f] + fDof;
5341:           fEnd[f+1]   = fStart[f+1];
5342:         }
5343:         PetscSectionGetOffset(cSec, b, &bOff);
5344:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);

5346:         fAnchorStart[0] = 0;
5347:         fAnchorEnd[0]   = 0;
5348:         for (f = 0; f < numFields; f++) {
5349:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5351:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5352:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5353:         }
5354:         PetscSectionGetOffset(aSec, b, &bOff);
5355:         for (q = 0; q < bDof; q++) {
5356:           PetscInt a = anchors[bOff + q], aOff;

5358:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5359:           newPoints[2*(newP + q)]     = a;
5360:           newPoints[2*(newP + q) + 1] = 0;
5361:           PetscSectionGetOffset(section, a, &aOff);
5362:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);
5363:         }
5364:         newP += bDof;

5366:         if (outValues) {
5367:           /* get the point-to-point submatrix */
5368:           for (f = 0; f < numFields; f++) {
5369:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5370:           }
5371:         }
5372:       }
5373:       else {
5374:         newPoints[2 * newP]     = b;
5375:         newPoints[2 * newP + 1] = o;
5376:         newP++;
5377:       }
5378:     }
5379:   } else {
5380:     for (p = 0; p < numPoints; p++) {
5381:       PetscInt b    = points[2*p];
5382:       PetscInt o    = points[2*p+1];
5383:       PetscInt bDof = 0, bSecDof;

5385:       PetscSectionGetDof(section, b, &bSecDof);
5386:       if (!bSecDof) {
5387:         continue;
5388:       }
5389:       if (b >= aStart && b < aEnd) {
5390:         PetscSectionGetDof(aSec, b, &bDof);
5391:       }
5392:       if (bDof) {
5393:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5404:           newPoints[2*(newP + q)]     = a;
5405:           newPoints[2*(newP + q) + 1] = 0;
5406:           PetscSectionGetOffset(section, a, &aOff);
5407:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);
5408:         }
5409:         newP += bDof;

5411:         /* get the point-to-point submatrix */
5412:         if (outValues) {
5413:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5414:         }
5415:       }
5416:       else {
5417:         newPoints[2 * newP]     = b;
5418:         newPoints[2 * newP + 1] = o;
5419:         newP++;
5420:       }
5421:     }
5422:   }

5424:   if (outValues) {
5425:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5426:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5427:     /* multiply constraints on the right */
5428:     if (numFields) {
5429:       for (f = 0; f < numFields; f++) {
5430:         PetscInt oldOff = offsets[f];

5432:         for (p = 0; p < numPoints; p++) {
5433:           PetscInt cStart = newPointOffsets[f][p];
5434:           PetscInt b      = points[2 * p];
5435:           PetscInt c, r, k;
5436:           PetscInt dof;

5438:           PetscSectionGetFieldDof(section,b,f,&dof);
5439:           if (!dof) {
5440:             continue;
5441:           }
5442:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5443:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5444:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5446:             for (r = 0; r < numIndices; r++) {
5447:               for (c = 0; c < nCols; c++) {
5448:                 for (k = 0; k < dof; k++) {
5449:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5450:                 }
5451:               }
5452:             }
5453:           }
5454:           else {
5455:             /* copy this column as is */
5456:             for (r = 0; r < numIndices; r++) {
5457:               for (c = 0; c < dof; c++) {
5458:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5459:               }
5460:             }
5461:           }
5462:           oldOff += dof;
5463:         }
5464:       }
5465:     }
5466:     else {
5467:       PetscInt oldOff = 0;
5468:       for (p = 0; p < numPoints; p++) {
5469:         PetscInt cStart = newPointOffsets[0][p];
5470:         PetscInt b      = points[2 * p];
5471:         PetscInt c, r, k;
5472:         PetscInt dof;

5474:         PetscSectionGetDof(section,b,&dof);
5475:         if (!dof) {
5476:           continue;
5477:         }
5478:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5479:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5480:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5482:           for (r = 0; r < numIndices; r++) {
5483:             for (c = 0; c < nCols; c++) {
5484:               for (k = 0; k < dof; k++) {
5485:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5486:               }
5487:             }
5488:           }
5489:         }
5490:         else {
5491:           /* copy this column as is */
5492:           for (r = 0; r < numIndices; r++) {
5493:             for (c = 0; c < dof; c++) {
5494:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5495:             }
5496:           }
5497:         }
5498:         oldOff += dof;
5499:       }
5500:     }

5502:     if (multiplyLeft) {
5503:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5504:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5505:       /* multiply constraints transpose on the left */
5506:       if (numFields) {
5507:         for (f = 0; f < numFields; f++) {
5508:           PetscInt oldOff = offsets[f];

5510:           for (p = 0; p < numPoints; p++) {
5511:             PetscInt rStart = newPointOffsets[f][p];
5512:             PetscInt b      = points[2 * p];
5513:             PetscInt c, r, k;
5514:             PetscInt dof;

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

5521:               for (r = 0; r < nRows; r++) {
5522:                 for (c = 0; c < newNumIndices; c++) {
5523:                   for (k = 0; k < dof; k++) {
5524:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5525:                   }
5526:                 }
5527:               }
5528:             }
5529:             else {
5530:               /* copy this row as is */
5531:               for (r = 0; r < dof; r++) {
5532:                 for (c = 0; c < newNumIndices; c++) {
5533:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5534:                 }
5535:               }
5536:             }
5537:             oldOff += dof;
5538:           }
5539:         }
5540:       }
5541:       else {
5542:         PetscInt oldOff = 0;

5544:         for (p = 0; p < numPoints; p++) {
5545:           PetscInt rStart = newPointOffsets[0][p];
5546:           PetscInt b      = points[2 * p];
5547:           PetscInt c, r, k;
5548:           PetscInt dof;

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

5555:             for (r = 0; r < nRows; r++) {
5556:               for (c = 0; c < newNumIndices; c++) {
5557:                 for (k = 0; k < dof; k++) {
5558:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5559:                 }
5560:               }
5561:             }
5562:           }
5563:           else {
5564:             /* copy this row as is */
5565:             for (r = 0; r < dof; r++) {
5566:               for (c = 0; c < newNumIndices; c++) {
5567:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5568:               }
5569:             }
5570:           }
5571:           oldOff += dof;
5572:         }
5573:       }

5575:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5576:     }
5577:     else {
5578:       newValues = tmpValues;
5579:     }
5580:   }

5582:   /* clean up */
5583:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5584:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5586:   if (numFields) {
5587:     for (f = 0; f < numFields; f++) {
5588:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5589:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5590:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5591:     }
5592:   }
5593:   else {
5594:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5595:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5596:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5597:   }
5598:   ISRestoreIndices(aIS,&anchors);

5600:   /* output */
5601:   if (outPoints) {
5602:     *outPoints = newPoints;
5603:   }
5604:   else {
5605:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5606:   }
5607:   if (outValues) {
5608:     *outValues = newValues;
5609:   }
5610:   for (f = 0; f <= numFields; f++) {
5611:     offsets[f] = newOffsets[f];
5612:   }
5613:   return(0);
5614: }

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

5619:   Not collective

5621:   Input Parameters:
5622: + dm - The DM
5623: . section - The section describing the layout in v, or NULL to use the default section
5624: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5625: - point - The mesh point

5627:   Output parameters:
5628: + numIndices - The number of indices
5629: . indices - The indices
5630: - outOffsets - Field offset if not NULL

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

5634:   Level: advanced

5636: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5637: @*/
5638: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5639: {
5640:   PetscSection    clSection;
5641:   IS              clPoints;
5642:   const PetscInt *clp, *clperm;
5643:   const PetscInt  **perms[32] = {NULL};
5644:   PetscInt       *points = NULL, *pointsNew;
5645:   PetscInt        numPoints, numPointsNew;
5646:   PetscInt        offsets[32];
5647:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5648:   PetscErrorCode  ierr;

5656:   PetscSectionGetNumFields(section, &Nf);
5657:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5658:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5659:   /* Get points in closure */
5660:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5661:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5662:   /* Get number of indices and indices per field */
5663:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5664:     PetscInt dof, fdof;

5666:     PetscSectionGetDof(section, points[p], &dof);
5667:     for (f = 0; f < Nf; ++f) {
5668:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5669:       offsets[f+1] += fdof;
5670:     }
5671:     Nind += dof;
5672:   }
5673:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5674:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5675:   if (!Nf) offsets[1] = Nind;
5676:   /* Get dual space symmetries */
5677:   for (f = 0; f < PetscMax(1,Nf); f++) {
5678:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5679:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5680:   }
5681:   /* Correct for hanging node constraints */
5682:   {
5683:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5684:     if (numPointsNew) {
5685:       for (f = 0; f < PetscMax(1,Nf); f++) {
5686:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5687:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5688:       }
5689:       for (f = 0; f < PetscMax(1,Nf); f++) {
5690:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5691:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5692:       }
5693:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5694:       numPoints = numPointsNew;
5695:       Nind      = NindNew;
5696:       points    = pointsNew;
5697:     }
5698:   }
5699:   /* Calculate indices */
5700:   DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5701:   if (Nf) {
5702:     if (outOffsets) {
5703:       PetscInt f;

5705:       for (f = 0; f <= Nf; f++) {
5706:         outOffsets[f] = offsets[f];
5707:       }
5708:     }
5709:     for (p = 0; p < numPoints; p++) {
5710:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5711:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);
5712:     }
5713:   } else {
5714:     for (p = 0, off = 0; p < numPoints; p++) {
5715:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5717:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5718:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, *indices);
5719:     }
5720:   }
5721:   /* Cleanup points */
5722:   for (f = 0; f < PetscMax(1,Nf); f++) {
5723:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5724:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5725:   }
5726:   if (numPointsNew) {
5727:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5728:   } else {
5729:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5730:   }
5731:   if (numIndices) *numIndices = Nind;
5732:   return(0);
5733: }

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

5738:   Not collective

5740:   Input Parameters:
5741: + dm - The DM
5742: . section - The section describing the layout in v, or NULL to use the default section
5743: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5744: . point - The mesh point
5745: . numIndices - The number of indices
5746: . indices - The indices
5747: - outOffsets - Field offset if not NULL

5749:   Level: advanced

5751: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5752: @*/
5753: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5754: {

5760:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5761:   return(0);
5762: }

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

5767:   Not collective

5769:   Input Parameters:
5770: + dm - The DM
5771: . section - The section describing the layout in v, or NULL to use the default section
5772: . globalSection - The section describing the layout in v, or NULL to use the default global section
5773: . A - The matrix
5774: . point - The point in the DM
5775: . values - The array of values
5776: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5781:   Level: intermediate

5783: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5784: @*/
5785: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5786: {
5787:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5788:   PetscSection        clSection;
5789:   IS                  clPoints;
5790:   PetscInt           *points = NULL, *newPoints;
5791:   const PetscInt     *clp, *clperm;
5792:   PetscInt           *indices;
5793:   PetscInt            offsets[32];
5794:   const PetscInt    **perms[32] = {NULL};
5795:   const PetscScalar **flips[32] = {NULL};
5796:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5797:   PetscScalar        *valCopy = NULL;
5798:   PetscScalar        *newValues;
5799:   PetscErrorCode      ierr;

5803:   if (!section) {DMGetSection(dm, &section);}
5805:   if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5808:   PetscSectionGetNumFields(section, &numFields);
5809:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5810:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5811:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
5812:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5813:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5814:     PetscInt fdof;

5816:     PetscSectionGetDof(section, points[p], &dof);
5817:     for (f = 0; f < numFields; ++f) {
5818:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5819:       offsets[f+1] += fdof;
5820:     }
5821:     numIndices += dof;
5822:   }
5823:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5837:         if (!numFields) {
5838:           PetscSectionGetDof(section,point,&fdof);
5839:         } else {
5840:           PetscSectionGetFieldDof(section,point,f,&fdof);
5841:         }
5842:         if (flip) {
5843:           PetscInt i, j, k;

5845:           if (!valCopy) {
5846:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5847:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5848:             values = valCopy;
5849:           }
5850:           for (i = 0; i < fdof; i++) {
5851:             PetscScalar fval = flip[i];

5853:             for (k = 0; k < numIndices; k++) {
5854:               valCopy[numIndices * (foffset + i) + k] *= fval;
5855:               valCopy[numIndices * k + (foffset + i)] *= fval;
5856:             }
5857:           }
5858:         }
5859:         foffset += fdof;
5860:       }
5861:     }
5862:   }
5863:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5864:   if (newNumPoints) {
5865:     if (valCopy) {
5866:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5867:     }
5868:     for (f = 0; f < PetscMax(1,numFields); f++) {
5869:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5870:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5871:     }
5872:     for (f = 0; f < PetscMax(1,numFields); f++) {
5873:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5874:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5875:     }
5876:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5877:     numPoints  = newNumPoints;
5878:     numIndices = newNumIndices;
5879:     points     = newPoints;
5880:     values     = newValues;
5881:   }
5882:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5883:   if (numFields) {
5884:     PetscBool useFieldOffsets;

5886:     PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
5887:     if (useFieldOffsets) {
5888:       for (p = 0; p < numPoints; p++) {
5889:         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, clperm, indices);
5890:       }
5891:     } else {
5892:       for (p = 0; p < numPoints; p++) {
5893:         PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5894:         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices);
5895:       }
5896:     }
5897:   } else {
5898:     for (p = 0, off = 0; p < numPoints; p++) {
5899:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5900:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5901:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices);
5902:     }
5903:   }
5904:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5905:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5906:   if (mesh->printFEM > 1) {
5907:     PetscInt i;
5908:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5909:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5910:     PetscPrintf(PETSC_COMM_SELF, "\n");
5911:   }
5912:   if (ierr) {
5913:     PetscMPIInt    rank;
5914:     PetscErrorCode ierr2;

5916:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5917:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5918:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5919:     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5920: 
5921:   }
5922:   for (f = 0; f < PetscMax(1,numFields); f++) {
5923:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5924:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5925:   }
5926:   if (newNumPoints) {
5927:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5928:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5929:   }
5930:   else {
5931:     if (valCopy) {
5932:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5933:     }
5934:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5935:   }
5936:   DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
5937:   return(0);
5938: }

5940: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5941: {
5942:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5943:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5944:   PetscInt       *cpoints = NULL;
5945:   PetscInt       *findices, *cindices;
5946:   const PetscInt *fclperm, *cclperm;
5947:   PetscInt        foffsets[32], coffsets[32];
5948:   CellRefiner     cellRefiner;
5949:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5950:   PetscErrorCode  ierr;

5955:   if (!fsection) {DMGetSection(dmf, &fsection);}
5957:   if (!csection) {DMGetSection(dmc, &csection);}
5959:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
5961:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
5964:   PetscSectionGetNumFields(fsection, &numFields);
5965:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5966:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5967:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5968:   PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
5969:   PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
5970:   /* Column indices */
5971:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5972:   maxFPoints = numCPoints;
5973:   /* Compress out points not in the section */
5974:   /*   TODO: Squeeze out points with 0 dof as well */
5975:   PetscSectionGetChart(csection, &pStart, &pEnd);
5976:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5977:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5978:       cpoints[q*2]   = cpoints[p];
5979:       cpoints[q*2+1] = cpoints[p+1];
5980:       ++q;
5981:     }
5982:   }
5983:   numCPoints = q;
5984:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5985:     PetscInt fdof;

5987:     PetscSectionGetDof(csection, cpoints[p], &dof);
5988:     if (!dof) continue;
5989:     for (f = 0; f < numFields; ++f) {
5990:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5991:       coffsets[f+1] += fdof;
5992:     }
5993:     numCIndices += dof;
5994:   }
5995:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5996:   /* Row indices */
5997:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5998:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5999:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6000:   for (r = 0, q = 0; r < numSubcells; ++r) {
6001:     /* TODO Map from coarse to fine cells */
6002:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6003:     /* Compress out points not in the section */
6004:     PetscSectionGetChart(fsection, &pStart, &pEnd);
6005:     for (p = 0; p < numFPoints*2; p += 2) {
6006:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6007:         PetscSectionGetDof(fsection, fpoints[p], &dof);
6008:         if (!dof) continue;
6009:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6010:         if (s < q) continue;
6011:         ftotpoints[q*2]   = fpoints[p];
6012:         ftotpoints[q*2+1] = fpoints[p+1];
6013:         ++q;
6014:       }
6015:     }
6016:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6017:   }
6018:   numFPoints = q;
6019:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6020:     PetscInt fdof;

6022:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6023:     if (!dof) continue;
6024:     for (f = 0; f < numFields; ++f) {
6025:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6026:       foffsets[f+1] += fdof;
6027:     }
6028:     numFIndices += dof;
6029:   }
6030:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

6032:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6033:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6034:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6035:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6036:   if (numFields) {
6037:     const PetscInt **permsF[32] = {NULL};
6038:     const PetscInt **permsC[32] = {NULL};

6040:     for (f = 0; f < numFields; f++) {
6041:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6042:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6043:     }
6044:     for (p = 0; p < numFPoints; p++) {
6045:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6046:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6047:     }
6048:     for (p = 0; p < numCPoints; p++) {
6049:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6050:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6051:     }
6052:     for (f = 0; f < numFields; f++) {
6053:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6054:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6055:     }
6056:   } else {
6057:     const PetscInt **permsF = NULL;
6058:     const PetscInt **permsC = NULL;

6060:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6061:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6062:     for (p = 0, off = 0; p < numFPoints; p++) {
6063:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6065:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6066:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6067:     }
6068:     for (p = 0, off = 0; p < numCPoints; p++) {
6069:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6071:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6072:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6073:     }
6074:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6075:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6076:   }
6077:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
6078:   /* TODO: flips */
6079:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6080:   if (ierr) {
6081:     PetscMPIInt    rank;
6082:     PetscErrorCode ierr2;

6084:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6085:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6086:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6087:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6088:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6089: 
6090:   }
6091:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6092:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6093:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6094:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6095:   return(0);
6096: }

6098: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6099: {
6100:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
6101:   PetscInt      *cpoints = NULL;
6102:   PetscInt       foffsets[32], coffsets[32];
6103:   const PetscInt *fclperm, *cclperm;
6104:   CellRefiner    cellRefiner;
6105:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

6111:   if (!fsection) {DMGetSection(dmf, &fsection);}
6113:   if (!csection) {DMGetSection(dmc, &csection);}
6115:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6117:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6119:   PetscSectionGetNumFields(fsection, &numFields);
6120:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6121:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
6122:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
6123:   PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);
6124:   PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);
6125:   /* Column indices */
6126:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6127:   maxFPoints = numCPoints;
6128:   /* Compress out points not in the section */
6129:   /*   TODO: Squeeze out points with 0 dof as well */
6130:   PetscSectionGetChart(csection, &pStart, &pEnd);
6131:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6132:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6133:       cpoints[q*2]   = cpoints[p];
6134:       cpoints[q*2+1] = cpoints[p+1];
6135:       ++q;
6136:     }
6137:   }
6138:   numCPoints = q;
6139:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6140:     PetscInt fdof;

6142:     PetscSectionGetDof(csection, cpoints[p], &dof);
6143:     if (!dof) continue;
6144:     for (f = 0; f < numFields; ++f) {
6145:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6146:       coffsets[f+1] += fdof;
6147:     }
6148:     numCIndices += dof;
6149:   }
6150:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6151:   /* Row indices */
6152:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6153:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6154:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6155:   for (r = 0, q = 0; r < numSubcells; ++r) {
6156:     /* TODO Map from coarse to fine cells */
6157:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6158:     /* Compress out points not in the section */
6159:     PetscSectionGetChart(fsection, &pStart, &pEnd);
6160:     for (p = 0; p < numFPoints*2; p += 2) {
6161:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6162:         PetscSectionGetDof(fsection, fpoints[p], &dof);
6163:         if (!dof) continue;
6164:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6165:         if (s < q) continue;
6166:         ftotpoints[q*2]   = fpoints[p];
6167:         ftotpoints[q*2+1] = fpoints[p+1];
6168:         ++q;
6169:       }
6170:     }
6171:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6172:   }
6173:   numFPoints = q;
6174:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6175:     PetscInt fdof;

6177:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6178:     if (!dof) continue;
6179:     for (f = 0; f < numFields; ++f) {
6180:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6181:       foffsets[f+1] += fdof;
6182:     }
6183:     numFIndices += dof;
6184:   }
6185:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

6193:     for (f = 0; f < numFields; f++) {
6194:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6195:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6196:     }
6197:     for (p = 0; p < numFPoints; p++) {
6198:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6199:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6200:     }
6201:     for (p = 0; p < numCPoints; p++) {
6202:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6203:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6204:     }
6205:     for (f = 0; f < numFields; f++) {
6206:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6207:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6208:     }
6209:   } else {
6210:     const PetscInt **permsF = NULL;
6211:     const PetscInt **permsC = NULL;

6213:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6214:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6215:     for (p = 0, off = 0; p < numFPoints; p++) {
6216:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6218:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6219:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6220:     }
6221:     for (p = 0, off = 0; p < numCPoints; p++) {
6222:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6224:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6225:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6226:     }
6227:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6228:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6229:   }
6230:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6231:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6232:   return(0);
6233: }

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

6238:   Input Parameter:
6239: . dm - The DMPlex object

6241:   Output Parameters:
6242: + cMax - The first hybrid cell
6243: . fMax - The first hybrid face
6244: . eMax - The first hybrid edge
6245: - vMax - The first hybrid vertex

6247:   Level: developer

6249: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6250: @*/
6251: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6252: {
6253:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6254:   PetscInt       dim;

6259:   DMGetDimension(dm, &dim);
6260:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6261:   if (cMax) *cMax = mesh->hybridPointMax[dim];
6262:   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6263:   if (eMax) *eMax = mesh->hybridPointMax[1];
6264:   if (vMax) *vMax = mesh->hybridPointMax[0];
6265:   return(0);
6266: }

6268: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6269: {
6270:   IS             is, his;
6271:   PetscInt       first = 0, stride;
6272:   PetscBool      isStride;

6276:   DMLabelGetStratumIS(depthLabel, d, &is);
6277:   PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6278:   if (isStride) {
6279:     ISStrideGetInfo(is, &first, &stride);
6280:   }
6281:   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6282:   ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6283:   DMLabelSetStratumIS(dimLabel, d, his);
6284:   ISDestroy(&his);
6285:   ISDestroy(&is);
6286:   return(0);
6287: }

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

6292:   Input Parameters:
6293: . dm   - The DMPlex object
6294: . cMax - The first hybrid cell
6295: . fMax - The first hybrid face
6296: . eMax - The first hybrid edge
6297: - vMax - The first hybrid vertex

6299:   Level: developer

6301: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6302: @*/
6303: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6304: {
6305:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6306:   PetscInt       dim;

6311:   DMGetDimension(dm, &dim);
6312:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6313:   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6314:   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6315:   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6316:   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6317:   return(0);
6318: }

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

6323:   Input Parameter:
6324: . dm   - The DMPlex object

6326:   Output Parameter:
6327: . cellHeight - The height of a cell

6329:   Level: developer

6331: .seealso DMPlexSetVTKCellHeight()
6332: @*/
6333: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6334: {
6335:   DM_Plex *mesh = (DM_Plex*) dm->data;

6340:   *cellHeight = mesh->vtkCellHeight;
6341:   return(0);
6342: }

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

6347:   Input Parameters:
6348: + dm   - The DMPlex object
6349: - cellHeight - The height of a cell

6351:   Level: developer

6353: .seealso DMPlexGetVTKCellHeight()
6354: @*/
6355: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6356: {
6357:   DM_Plex *mesh = (DM_Plex*) dm->data;

6361:   mesh->vtkCellHeight = cellHeight;
6362:   return(0);
6363: }

6365: /* We can easily have a form that takes an IS instead */
6366: PetscErrorCode DMPlexCreateNumbering_Internal(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6367: {
6368:   PetscSection   section, globalSection;
6369:   PetscInt      *numbers, p;

6373:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6374:   PetscSectionSetChart(section, pStart, pEnd);
6375:   for (p = pStart; p < pEnd; ++p) {
6376:     PetscSectionSetDof(section, p, 1);
6377:   }
6378:   PetscSectionSetUp(section);
6379:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6380:   PetscMalloc1(pEnd - pStart, &numbers);
6381:   for (p = pStart; p < pEnd; ++p) {
6382:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6383:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6384:     else                       numbers[p-pStart] += shift;
6385:   }
6386:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6387:   if (globalSize) {
6388:     PetscLayout layout;
6389:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6390:     PetscLayoutGetSize(layout, globalSize);
6391:     PetscLayoutDestroy(&layout);
6392:   }
6393:   PetscSectionDestroy(&section);
6394:   PetscSectionDestroy(&globalSection);
6395:   return(0);
6396: }

6398: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6399: {
6400:   PetscInt       cellHeight, cStart, cEnd, cMax;

6404:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6405:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6406:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6407:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6408:   DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6409:   return(0);
6410: }

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

6415:   Input Parameter:
6416: . dm   - The DMPlex object

6418:   Output Parameter:
6419: . globalCellNumbers - Global cell numbers for all cells on this process

6421:   Level: developer

6423: .seealso DMPlexGetVertexNumbering()
6424: @*/
6425: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6426: {
6427:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6432:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6433:   *globalCellNumbers = mesh->globalCellNumbers;
6434:   return(0);
6435: }

6437: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6438: {
6439:   PetscInt       vStart, vEnd, vMax;

6444:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6445:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6446:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6447:   DMPlexCreateNumbering_Internal(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6448:   return(0);
6449: }

6451: /*@
6452:   DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process

6454:   Input Parameter:
6455: . dm   - The DMPlex object

6457:   Output Parameter:
6458: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6460:   Level: developer

6462: .seealso DMPlexGetCellNumbering()
6463: @*/
6464: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6465: {
6466:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6471:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6472:   *globalVertexNumbers = mesh->globalVertexNumbers;
6473:   return(0);
6474: }

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

6479:   Input Parameter:
6480: . dm   - The DMPlex object

6482:   Output Parameter:
6483: . globalPointNumbers - Global numbers for all points on this process

6485:   Level: developer

6487: .seealso DMPlexGetCellNumbering()
6488: @*/
6489: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6490: {
6491:   IS             nums[4];
6492:   PetscInt       depths[4], gdepths[4], starts[4];
6493:   PetscInt       depth, d, shift = 0;

6498:   DMPlexGetDepth(dm, &depth);
6499:   /* For unstratified meshes use dim instead of depth */
6500:   if (depth < 0) {DMGetDimension(dm, &depth);}
6501:   for (d = 0; d <= depth; ++d) {
6502:     PetscInt end;

6504:     depths[d] = depth-d;
6505:     DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);
6506:     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6507:   }
6508:   PetscSortIntWithArray(depth+1, starts, depths);
6509:   MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
6510:   for (d = 0; d <= depth; ++d) {
6511:     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6512:   }
6513:   for (d = 0; d <= depth; ++d) {
6514:     PetscInt pStart, pEnd, gsize;

6516:     DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);
6517:     DMPlexCreateNumbering_Internal(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6518:     shift += gsize;
6519:   }
6520:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6521:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6522:   return(0);
6523: }


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

6529:   Input Parameter:
6530: . dm - The DMPlex object

6532:   Output Parameter:
6533: . ranks - The rank field

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

6538:   Level: intermediate

6540: .seealso: DMView()
6541: @*/
6542: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6543: {
6544:   DM             rdm;
6545:   PetscFE        fe;
6546:   PetscScalar   *r;
6547:   PetscMPIInt    rank;
6548:   PetscInt       dim, cStart, cEnd, c;

6554:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6555:   DMClone(dm, &rdm);
6556:   DMGetDimension(rdm, &dim);
6557:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);
6558:   PetscObjectSetName((PetscObject) fe, "rank");
6559:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6560:   PetscFEDestroy(&fe);
6561:   DMCreateDS(rdm);
6562:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6563:   DMCreateGlobalVector(rdm, ranks);
6564:   PetscObjectSetName((PetscObject) *ranks, "partition");
6565:   VecGetArray(*ranks, &r);
6566:   for (c = cStart; c < cEnd; ++c) {
6567:     PetscScalar *lr;

6569:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6570:     *lr = rank;
6571:   }
6572:   VecRestoreArray(*ranks, &r);
6573:   DMDestroy(&rdm);
6574:   return(0);
6575: }

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

6580:   Input Parameters:
6581: + dm    - The DMPlex
6582: - label - The DMLabel

6584:   Output Parameter:
6585: . val - The label value field

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

6590:   Level: intermediate

6592: .seealso: DMView()
6593: @*/
6594: PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6595: {
6596:   DM             rdm;
6597:   PetscFE        fe;
6598:   PetscScalar   *v;
6599:   PetscInt       dim, cStart, cEnd, c;

6606:   DMClone(dm, &rdm);
6607:   DMGetDimension(rdm, &dim);
6608:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);
6609:   PetscObjectSetName((PetscObject) fe, "label_value");
6610:   DMSetField(rdm, 0, NULL, (PetscObject) fe);
6611:   PetscFEDestroy(&fe);
6612:   DMCreateDS(rdm);
6613:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6614:   DMCreateGlobalVector(rdm, val);
6615:   PetscObjectSetName((PetscObject) *val, "label_value");
6616:   VecGetArray(*val, &v);
6617:   for (c = cStart; c < cEnd; ++c) {
6618:     PetscScalar *lv;
6619:     PetscInt     cval;

6621:     DMPlexPointGlobalRef(rdm, c, v, &lv);
6622:     DMLabelGetValue(label, c, &cval);
6623:     *lv = cval;
6624:   }
6625:   VecRestoreArray(*val, &v);
6626:   DMDestroy(&rdm);
6627:   return(0);
6628: }

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

6633:   Input Parameter:
6634: . dm - The DMPlex object

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

6638:   Level: developer

6640: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6641: @*/
6642: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6643: {
6644:   PetscSection    coneSection, supportSection;
6645:   const PetscInt *cone, *support;
6646:   PetscInt        coneSize, c, supportSize, s;
6647:   PetscInt        pStart, pEnd, p, pp, csize, ssize;
6648:   PetscBool       storagecheck = PETSC_TRUE;
6649:   PetscErrorCode  ierr;

6653:   DMPlexGetConeSection(dm, &coneSection);
6654:   DMPlexGetSupportSection(dm, &supportSection);
6655:   /* Check that point p is found in the support of its cone points, and vice versa */
6656:   DMPlexGetChart(dm, &pStart, &pEnd);
6657:   for (p = pStart; p < pEnd; ++p) {
6658:     DMPlexGetConeSize(dm, p, &coneSize);
6659:     DMPlexGetCone(dm, p, &cone);
6660:     for (c = 0; c < coneSize; ++c) {
6661:       PetscBool dup = PETSC_FALSE;
6662:       PetscInt  d;
6663:       for (d = c-1; d >= 0; --d) {
6664:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6665:       }
6666:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6667:       DMPlexGetSupport(dm, cone[c], &support);
6668:       for (s = 0; s < supportSize; ++s) {
6669:         if (support[s] == p) break;
6670:       }
6671:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6672:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6673:         for (s = 0; s < coneSize; ++s) {
6674:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6675:         }
6676:         PetscPrintf(PETSC_COMM_SELF, "\n");
6677:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6678:         for (s = 0; s < supportSize; ++s) {
6679:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6680:         }
6681:         PetscPrintf(PETSC_COMM_SELF, "\n");
6682:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6683:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6684:       }
6685:     }
6686:     DMPlexGetTreeParent(dm, p, &pp, NULL);
6687:     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
6688:     DMPlexGetSupportSize(dm, p, &supportSize);
6689:     DMPlexGetSupport(dm, p, &support);
6690:     for (s = 0; s < supportSize; ++s) {
6691:       DMPlexGetConeSize(dm, support[s], &coneSize);
6692:       DMPlexGetCone(dm, support[s], &cone);
6693:       for (c = 0; c < coneSize; ++c) {
6694:         DMPlexGetTreeParent(dm, cone[c], &pp, NULL);
6695:         if (cone[c] != pp) { c = 0; break; }
6696:         if (cone[c] == p) break;
6697:       }
6698:       if (c >= coneSize) {
6699:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6700:         for (c = 0; c < supportSize; ++c) {
6701:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6702:         }
6703:         PetscPrintf(PETSC_COMM_SELF, "\n");
6704:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6705:         for (c = 0; c < coneSize; ++c) {
6706:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6707:         }
6708:         PetscPrintf(PETSC_COMM_SELF, "\n");
6709:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6710:       }
6711:     }
6712:   }
6713:   if (storagecheck) {
6714:     PetscSectionGetStorageSize(coneSection, &csize);
6715:     PetscSectionGetStorageSize(supportSection, &ssize);
6716:     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6717:   }
6718:   return(0);
6719: }

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

6724:   Input Parameters:
6725: + dm - The DMPlex object
6726: - cellHeight - Normally 0

6728:   Note: This is a useful diagnostic when creating meshes programmatically.
6729:   Currently applicable only to homogeneous simplex or tensor meshes.

6731:   Level: developer

6733: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6734: @*/
6735: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
6736: {
6737:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6738:   PetscBool      isSimplex = PETSC_FALSE;

6743:   DMGetDimension(dm, &dim);
6744:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6745:   if (cStart < cEnd) {
6746:     DMPlexGetConeSize(dm, cStart, &c);
6747:     isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE;
6748:   }
6749:   switch (dim) {
6750:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6751:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6752:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6753:   default:
6754:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6755:   }
6756:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6757:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6758:   cMax = cMax >= 0 ? cMax : cEnd;
6759:   for (c = cStart; c < cMax; ++c) {
6760:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6762:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6763:     for (cl = 0; cl < closureSize*2; cl += 2) {
6764:       const PetscInt p = closure[cl];
6765:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6766:     }
6767:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6768:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6769:   }
6770:   for (c = cMax; c < cEnd; ++c) {
6771:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6773:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6774:     for (cl = 0; cl < closureSize*2; cl += 2) {
6775:       const PetscInt p = closure[cl];
6776:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6777:     }
6778:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6779:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6780:   }
6781:   return(0);
6782: }

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

6787:   Input Parameters:
6788: + dm - The DMPlex object
6789: - cellHeight - Normally 0

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

6793:   Level: developer

6795: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6796: @*/
6797: PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
6798: {
6799:   PetscInt       pMax[4];
6800:   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;

6805:   DMGetDimension(dm, &dim);
6806:   DMPlexGetDepth(dm, &depth);
6807:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6808:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6809:   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
6810:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6811:     for (c = cStart; c < cEnd; ++c) {
6812:       const PetscInt *cone, *ornt, *faces;
6813:       PetscInt        numFaces, faceSize, coneSize,f;
6814:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6816:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6817:       DMPlexGetConeSize(dm, c, &coneSize);
6818:       DMPlexGetCone(dm, c, &cone);
6819:       DMPlexGetConeOrientation(dm, c, &ornt);
6820:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6821:       for (cl = 0; cl < closureSize*2; cl += 2) {
6822:         const PetscInt p = closure[cl];
6823:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6824:       }
6825:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6826:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6827:       for (f = 0; f < numFaces; ++f) {
6828:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6830:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6831:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6832:           const PetscInt p = fclosure[cl];
6833:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6834:         }
6835:         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);
6836:         for (v = 0; v < fnumCorners; ++v) {
6837:           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]);
6838:         }
6839:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6840:       }
6841:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6842:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6843:     }
6844:   }
6845:   return(0);
6846: }

6848: /*@
6849:   DMPlexCheckGeometry - Check the geometry of mesh cells

6851:   Input Parameter:
6852: . dm - The DMPlex object

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

6856:   Level: developer

6858: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton(), DMCheckFaces()
6859: @*/
6860: PetscErrorCode DMPlexCheckGeometry(DM dm)
6861: {
6862:   PetscReal      detJ, J[9], refVol = 1.0;
6863:   PetscReal      vol;
6864:   PetscInt       dim, depth, d, cStart, cEnd, c;

6868:   DMGetDimension(dm, &dim);
6869:   DMPlexGetDepth(dm, &depth);
6870:   for (d = 0; d < dim; ++d) refVol *= 2.0;
6871:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6872:   for (c = cStart; c < cEnd; ++c) {
6873:     DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);
6874:     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
6875:     PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);
6876:     if (depth > 1) {
6877:       DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);
6878:       if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
6879:       PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);
6880:     }
6881:   }
6882:   return(0);
6883: }

6885: static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
6886: {
6887:   PetscInt i,l,n;
6888:   const PetscInt *cone;

6892:   *missingPoint = -1;
6893:   DMPlexGetConeSize(dm, p, &n);
6894:   DMPlexGetCone(dm, p, &cone);
6895:   for (i=0; i<n; i++) {
6896:     PetscFindInt(cone[i], npoints, points, &l);
6897:     if (l < 0) {
6898:       *missingPoint = cone[i];
6899:       break;
6900:     }
6901:   }
6902:   return(0);
6903: }

6905: /*@
6906:   DMPlexCheckPointSF - Check that several sufficient conditions are met for the point SF of this plex.

6908:   Input Parameters:
6909: . dm - The DMPlex object

6911:   Note: This is mainly intended for debugging/testing purposes.

6913:   Level: developer

6915: .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6916: @*/
6917: PetscErrorCode DMPlexCheckPointSF(DM dm)
6918: {
6919:   PetscSF sf;
6920:   PetscInt d,depth,i,nleaves,p,plo,phi,missingPoint;
6921:   const PetscInt *locals;

6926:   DMPlexGetDepth(dm, &depth);
6927:   DMGetPointSF(dm, &sf);
6928:   PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);

6930:   /* 1) check there are no faces in 2D, cells in 3D, in interface */
6931:   DMPlexGetVTKCellHeight(dm, &d);
6932:   DMPlexGetHeightStratum(dm, d, &plo, &phi);
6933:   for (i=0; i<nleaves; i++) {
6934:     p = locals[i];
6935:     if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
6936:   }

6938:   /* 2) if some point is in interface, then all its cone points must be also in interface  */
6939:   for (i=0; i<nleaves; i++) {
6940:     p = locals[i];
6941:     DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);
6942:     if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
6943:   }
6944:   return(0);
6945: }

6947: typedef struct cell_stats
6948: {
6949:   PetscReal min, max, sum, squaresum;
6950:   PetscInt  count;
6951: } cell_stats_t;

6953: static void cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
6954: {
6955:   PetscInt i, N = *len;

6957:   for (i = 0; i < N; i++) {
6958:     cell_stats_t *A = (cell_stats_t *) a;
6959:     cell_stats_t *B = (cell_stats_t *) b;

6961:     B->min = PetscMin(A->min,B->min);
6962:     B->max = PetscMax(A->max,B->max);
6963:     B->sum += A->sum;
6964:     B->squaresum += A->squaresum;
6965:     B->count += A->count;
6966:   }
6967: }

6969: /*@
6970:   DMPlexCheckCellShape - Checks the Jacobian of the mapping and computes some minimal statistics.

6972:   Input Parameters:
6973: + dm - The DMPlex object
6974: - output - If true, statistics will be displayed on stdout

6976:   Note: This is mainly intended for debugging/testing purposes.

6978:   Level: developer

6980: .seealso: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6981: @*/
6982: PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output)
6983: {
6984:   PetscMPIInt    rank,size;
6985:   PetscInt       dim, c, cStart, cEnd, cMax, count = 0;
6986:   cell_stats_t   stats, globalStats;
6987:   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
6988:   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
6989:   DM             dmCoarse;

6994:   stats.min   = PETSC_MAX_REAL;
6995:   stats.max   = PETSC_MIN_REAL;
6996:   stats.sum   = stats.squaresum = 0.;
6997:   stats.count = 0;

6999:   DMGetCoordinateDim(dm,&dim);
7000:   PetscMalloc2(dim * dim, &J, dim * dim, &invJ);
7001:   DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);
7002:   DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);
7003:   cMax = cMax < 0 ? cEnd : cMax;
7004:   for (c = cStart; c < cMax; c++) {
7005:     PetscInt  i;
7006:     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;

7008:     DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);
7009:     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
7010:     for (i = 0; i < dim * dim; i++) {
7011:       frobJ    += J[i] * J[i];
7012:       frobInvJ += invJ[i] * invJ[i];
7013:     }
7014:     cond2 = frobJ * frobInvJ;
7015:     cond  = PetscSqrtReal(cond2);

7017:     stats.min        = PetscMin(stats.min,cond);
7018:     stats.max        = PetscMax(stats.max,cond);
7019:     stats.sum       += cond;
7020:     stats.squaresum += cond2;
7021:     stats.count++;
7022:   }

7024:   MPI_Comm_size(comm,&size);
7025:   if (size > 1) {
7026:     PetscMPIInt   blockLengths[2] = {4,1};
7027:     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
7028:     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
7029:     MPI_Op        statReduce;

7031:     MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);
7032:     MPI_Type_commit(&statType);
7033:     MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);
7034:     MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);
7035:     MPI_Op_free(&statReduce);
7036:     MPI_Type_free(&statType);
7037:   } else {
7038:     PetscMemcpy(&globalStats,&stats,sizeof(stats));
7039:   }

7041:   MPI_Comm_rank(comm,&rank);
7042:   if (!rank) {
7043:     count = globalStats.count;
7044:     min   = globalStats.min;
7045:     max   = globalStats.max;
7046:     mean  = globalStats.sum / globalStats.count;
7047:     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
7048:   }

7050:   if (output) {
7051:     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);
7052:   }
7053:   PetscFree2(J,invJ);

7055:   DMGetCoarseDM(dm,&dmCoarse);
7056:   if (dmCoarse) {
7057:     PetscBool isplex;

7059:     PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);
7060:     if (isplex) {
7061:       DMPlexCheckCellShape(dmCoarse,output);
7062:     }
7063:   }
7064:   return(0);
7065: }

7067: /* Pointwise interpolation
7068:      Just code FEM for now
7069:      u^f = I u^c
7070:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
7071:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
7072:      I_{ij} = psi^f_i phi^c_j
7073: */
7074: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
7075: {
7076:   PetscSection   gsc, gsf;
7077:   PetscInt       m, n;
7078:   void          *ctx;
7079:   DM             cdm;
7080:   PetscBool      regular, ismatis;

7084:   DMGetGlobalSection(dmFine, &gsf);
7085:   PetscSectionGetConstrainedStorageSize(gsf, &m);
7086:   DMGetGlobalSection(dmCoarse, &gsc);
7087:   PetscSectionGetConstrainedStorageSize(gsc, &n);

7089:   PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
7090:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
7091:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7092:   MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
7093:   DMGetApplicationContext(dmFine, &ctx);

7095:   DMGetCoarseDM(dmFine, &cdm);
7096:   DMPlexGetRegularRefinement(dmFine, &regular);
7097:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
7098:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
7099:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
7100:   if (scaling) {
7101:     /* Use naive scaling */
7102:     DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
7103:   }
7104:   return(0);
7105: }

7107: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
7108: {
7110:   VecScatter     ctx;

7113:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
7114:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
7115:   VecScatterDestroy(&ctx);
7116:   return(0);
7117: }

7119: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
7120: {
7121:   PetscSection   gsc, gsf;
7122:   PetscInt       m, n;
7123:   void          *ctx;
7124:   DM             cdm;
7125:   PetscBool      regular;

7129:   DMGetGlobalSection(dmFine, &gsf);
7130:   PetscSectionGetConstrainedStorageSize(gsf, &m);
7131:   DMGetGlobalSection(dmCoarse, &gsc);
7132:   PetscSectionGetConstrainedStorageSize(gsc, &n);

7134:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
7135:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
7136:   MatSetType(*mass, dmCoarse->mattype);
7137:   DMGetApplicationContext(dmFine, &ctx);

7139:   DMGetCoarseDM(dmFine, &cdm);
7140:   DMPlexGetRegularRefinement(dmFine, &regular);
7141:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
7142:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
7143:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
7144:   return(0);
7145: }

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

7150:   Input Parameter:
7151: . dm - The DMPlex object

7153:   Output Parameter:
7154: . regular - The flag

7156:   Level: intermediate

7158: .seealso: DMPlexSetRegularRefinement()
7159: @*/
7160: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7161: {
7165:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
7166:   return(0);
7167: }

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

7172:   Input Parameters:
7173: + dm - The DMPlex object
7174: - regular - The flag

7176:   Level: intermediate

7178: .seealso: DMPlexGetRegularRefinement()
7179: @*/
7180: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7181: {
7184:   ((DM_Plex *) dm->data)->regularRefinement = regular;
7185:   return(0);
7186: }

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

7193:   not collective

7195:   Input Parameters:
7196: . dm - The DMPlex object

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


7203:   Level: intermediate

7205: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7206: @*/
7207: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7208: {
7209:   DM_Plex *plex = (DM_Plex *)dm->data;

7214:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7215:   if (anchorSection) *anchorSection = plex->anchorSection;
7216:   if (anchorIS) *anchorIS = plex->anchorIS;
7217:   return(0);
7218: }

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

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

7228:   collective on dm

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

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

7237:   Level: intermediate

7239: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7240: @*/
7241: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7242: {
7243:   DM_Plex        *plex = (DM_Plex *)dm->data;
7244:   PetscMPIInt    result;

7249:   if (anchorSection) {
7251:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7252:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7253:   }
7254:   if (anchorIS) {
7256:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7257:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7258:   }

7260:   PetscObjectReference((PetscObject)anchorSection);
7261:   PetscSectionDestroy(&plex->anchorSection);
7262:   plex->anchorSection = anchorSection;

7264:   PetscObjectReference((PetscObject)anchorIS);
7265:   ISDestroy(&plex->anchorIS);
7266:   plex->anchorIS = anchorIS;

7268: #if defined(PETSC_USE_DEBUG)
7269:   if (anchorIS && anchorSection) {
7270:     PetscInt size, a, pStart, pEnd;
7271:     const PetscInt *anchors;

7273:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7274:     ISGetLocalSize(anchorIS,&size);
7275:     ISGetIndices(anchorIS,&anchors);
7276:     for (a = 0; a < size; a++) {
7277:       PetscInt p;

7279:       p = anchors[a];
7280:       if (p >= pStart && p < pEnd) {
7281:         PetscInt dof;

7283:         PetscSectionGetDof(anchorSection,p,&dof);
7284:         if (dof) {
7285:           PetscErrorCode ierr2;

7287:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7288:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7289:         }
7290:       }
7291:     }
7292:     ISRestoreIndices(anchorIS,&anchors);
7293:   }
7294: #endif
7295:   /* reset the generic constraints */
7296:   DMSetDefaultConstraints(dm,NULL,NULL);
7297:   return(0);
7298: }

7300: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7301: {
7302:   PetscSection anchorSection;
7303:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

7308:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7309:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
7310:   PetscSectionGetNumFields(section,&numFields);
7311:   if (numFields) {
7312:     PetscInt f;
7313:     PetscSectionSetNumFields(*cSec,numFields);

7315:     for (f = 0; f < numFields; f++) {
7316:       PetscInt numComp;

7318:       PetscSectionGetFieldComponents(section,f,&numComp);
7319:       PetscSectionSetFieldComponents(*cSec,f,numComp);
7320:     }
7321:   }
7322:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7323:   PetscSectionGetChart(section,&sStart,&sEnd);
7324:   pStart = PetscMax(pStart,sStart);
7325:   pEnd   = PetscMin(pEnd,sEnd);
7326:   pEnd   = PetscMax(pStart,pEnd);
7327:   PetscSectionSetChart(*cSec,pStart,pEnd);
7328:   for (p = pStart; p < pEnd; p++) {
7329:     PetscSectionGetDof(anchorSection,p,&dof);
7330:     if (dof) {
7331:       PetscSectionGetDof(section,p,&dof);
7332:       PetscSectionSetDof(*cSec,p,dof);
7333:       for (f = 0; f < numFields; f++) {
7334:         PetscSectionGetFieldDof(section,p,f,&dof);
7335:         PetscSectionSetFieldDof(*cSec,p,f,dof);
7336:       }
7337:     }
7338:   }
7339:   PetscSectionSetUp(*cSec);
7340:   return(0);
7341: }

7343: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7344: {
7345:   PetscSection aSec;
7346:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7347:   const PetscInt *anchors;
7348:   PetscInt numFields, f;
7349:   IS aIS;

7354:   PetscSectionGetStorageSize(cSec, &m);
7355:   PetscSectionGetStorageSize(section, &n);
7356:   MatCreate(PETSC_COMM_SELF,cMat);
7357:   MatSetSizes(*cMat,m,n,m,n);
7358:   MatSetType(*cMat,MATSEQAIJ);
7359:   DMPlexGetAnchors(dm,&aSec,&aIS);
7360:   ISGetIndices(aIS,&anchors);
7361:   /* cSec will be a subset of aSec and section */
7362:   PetscSectionGetChart(cSec,&pStart,&pEnd);
7363:   PetscMalloc1(m+1,&i);
7364:   i[0] = 0;
7365:   PetscSectionGetNumFields(section,&numFields);
7366:   for (p = pStart; p < pEnd; p++) {
7367:     PetscInt rDof, rOff, r;

7369:     PetscSectionGetDof(aSec,p,&rDof);
7370:     if (!rDof) continue;
7371:     PetscSectionGetOffset(aSec,p,&rOff);
7372:     if (numFields) {
7373:       for (f = 0; f < numFields; f++) {
7374:         annz = 0;
7375:         for (r = 0; r < rDof; r++) {
7376:           a = anchors[rOff + r];
7377:           PetscSectionGetFieldDof(section,a,f,&aDof);
7378:           annz += aDof;
7379:         }
7380:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7381:         PetscSectionGetFieldOffset(cSec,p,f,&off);
7382:         for (q = 0; q < dof; q++) {
7383:           i[off + q + 1] = i[off + q] + annz;
7384:         }
7385:       }
7386:     }
7387:     else {
7388:       annz = 0;
7389:       for (q = 0; q < dof; q++) {
7390:         a = anchors[off + q];
7391:         PetscSectionGetDof(section,a,&aDof);
7392:         annz += aDof;
7393:       }
7394:       PetscSectionGetDof(cSec,p,&dof);
7395:       PetscSectionGetOffset(cSec,p,&off);
7396:       for (q = 0; q < dof; q++) {
7397:         i[off + q + 1] = i[off + q] + annz;
7398:       }
7399:     }
7400:   }
7401:   nnz = i[m];
7402:   PetscMalloc1(nnz,&j);
7403:   offset = 0;
7404:   for (p = pStart; p < pEnd; p++) {
7405:     if (numFields) {
7406:       for (f = 0; f < numFields; f++) {
7407:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7408:         for (q = 0; q < dof; q++) {
7409:           PetscInt rDof, rOff, r;
7410:           PetscSectionGetDof(aSec,p,&rDof);
7411:           PetscSectionGetOffset(aSec,p,&rOff);
7412:           for (r = 0; r < rDof; r++) {
7413:             PetscInt s;

7415:             a = anchors[rOff + r];
7416:             PetscSectionGetFieldDof(section,a,f,&aDof);
7417:             PetscSectionGetFieldOffset(section,a,f,&aOff);
7418:             for (s = 0; s < aDof; s++) {
7419:               j[offset++] = aOff + s;
7420:             }
7421:           }
7422:         }
7423:       }
7424:     }
7425:     else {
7426:       PetscSectionGetDof(cSec,p,&dof);
7427:       for (q = 0; q < dof; q++) {
7428:         PetscInt rDof, rOff, r;
7429:         PetscSectionGetDof(aSec,p,&rDof);
7430:         PetscSectionGetOffset(aSec,p,&rOff);
7431:         for (r = 0; r < rDof; r++) {
7432:           PetscInt s;

7434:           a = anchors[rOff + r];
7435:           PetscSectionGetDof(section,a,&aDof);
7436:           PetscSectionGetOffset(section,a,&aOff);
7437:           for (s = 0; s < aDof; s++) {
7438:             j[offset++] = aOff + s;
7439:           }
7440:         }
7441:       }
7442:     }
7443:   }
7444:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7445:   PetscFree(i);
7446:   PetscFree(j);
7447:   ISRestoreIndices(aIS,&anchors);
7448:   return(0);
7449: }

7451: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7452: {
7453:   DM_Plex        *plex = (DM_Plex *)dm->data;
7454:   PetscSection   anchorSection, section, cSec;
7455:   Mat            cMat;

7460:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7461:   if (anchorSection) {
7462:     PetscInt Nf;

7464:     DMGetSection(dm,&section);
7465:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7466:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7467:     DMGetNumFields(dm,&Nf);
7468:     if (Nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7469:     DMSetDefaultConstraints(dm,cSec,cMat);
7470:     PetscSectionDestroy(&cSec);
7471:     MatDestroy(&cMat);
7472:   }
7473:   return(0);
7474: }

7476: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7477: {
7478:   IS             subis;
7479:   PetscSection   section, subsection;

7483:   DMGetDefaultSection(dm, &section);
7484:   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7485:   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7486:   /* Create subdomain */
7487:   DMPlexFilter(dm, label, value, subdm);
7488:   /* Create submodel */
7489:   DMPlexCreateSubpointIS(*subdm, &subis);
7490:   PetscSectionCreateSubmeshSection(section, subis, &subsection);
7491:   ISDestroy(&subis);
7492:   DMSetDefaultSection(*subdm, subsection);
7493:   PetscSectionDestroy(&subsection);
7494:   DMCopyDisc(dm, *subdm);
7495:   /* Create map from submodel to global model */
7496:   if (is) {
7497:     PetscSection    sectionGlobal, subsectionGlobal;
7498:     IS              spIS;
7499:     const PetscInt *spmap;
7500:     PetscInt       *subIndices;
7501:     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
7502:     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];

7504:     DMPlexCreateSubpointIS(*subdm, &spIS);
7505:     ISGetIndices(spIS, &spmap);
7506:     PetscSectionGetNumFields(section, &Nf);
7507:     DMGetDefaultGlobalSection(dm, &sectionGlobal);
7508:     DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);
7509:     PetscSectionGetChart(subsection, &pStart, &pEnd);
7510:     for (p = pStart; p < pEnd; ++p) {
7511:       PetscInt gdof, pSubSize  = 0;

7513:       PetscSectionGetDof(sectionGlobal, p, &gdof);
7514:       if (gdof > 0) {
7515:         for (f = 0; f < Nf; ++f) {
7516:           PetscInt fdof, fcdof;

7518:           PetscSectionGetFieldDof(subsection, p, f, &fdof);
7519:           PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7520:           pSubSize += fdof-fcdof;
7521:         }
7522:         subSize += pSubSize;
7523:         if (pSubSize) {
7524:           if (bs < 0) {
7525:             bs = pSubSize;
7526:           } else if (bs != pSubSize) {
7527:             /* Layout does not admit a pointwise block size */
7528:             bs = 1;
7529:           }
7530:         }
7531:       }
7532:     }
7533:     /* Must have same blocksize on all procs (some might have no points) */
7534:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7535:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7536:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7537:     else                            {bs = bsMinMax[0];}
7538:     PetscMalloc1(subSize, &subIndices);
7539:     for (p = pStart; p < pEnd; ++p) {
7540:       PetscInt gdof, goff;

7542:       PetscSectionGetDof(subsectionGlobal, p, &gdof);
7543:       if (gdof > 0) {
7544:         const PetscInt point = spmap[p];

7546:         PetscSectionGetOffset(sectionGlobal, point, &goff);
7547:         for (f = 0; f < Nf; ++f) {
7548:           PetscInt fdof, fcdof, fc, f2, poff = 0;

7550:           /* Can get rid of this loop by storing field information in the global section */
7551:           for (f2 = 0; f2 < f; ++f2) {
7552:             PetscSectionGetFieldDof(section, p, f2, &fdof);
7553:             PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7554:             poff += fdof-fcdof;
7555:           }
7556:           PetscSectionGetFieldDof(section, p, f, &fdof);
7557:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7558:           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7559:             subIndices[subOff] = goff+poff+fc;
7560:           }
7561:         }
7562:       }
7563:     }
7564:     ISRestoreIndices(spIS, &spmap);
7565:     ISDestroy(&spIS);
7566:     ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7567:     if (bs > 1) {
7568:       /* We need to check that the block size does not come from non-contiguous fields */
7569:       PetscInt i, j, set = 1;
7570:       for (i = 0; i < subSize; i += bs) {
7571:         for (j = 0; j < bs; ++j) {
7572:           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7573:         }
7574:       }
7575:       if (set) {ISSetBlockSize(*is, bs);}
7576:     }
7577:     /* Attach nullspace */
7578:     for (f = 0; f < Nf; ++f) {
7579:       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7580:       if ((*subdm)->nullspaceConstructors[f]) break;
7581:     }
7582:     if (f < Nf) {
7583:       MatNullSpace nullSpace;

7585:       (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7586:       PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7587:       MatNullSpaceDestroy(&nullSpace);
7588:     }
7589:   }
7590:   return(0);
7591: }