Actual source code: plex.c

petsc-3.10.2 2018-10-09
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_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;

 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, &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:     const char *vecname;
418:     PetscInt    n, nroots;

420:     if (dm->sfNatural) {
421:       VecGetLocalSize(originalv, &n);
422:       PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);
423:       if (n == nroots) {
424:         DMGetGlobalVector(dm, &v);
425:         DMPlexGlobalToNaturalBegin(dm, originalv, v);
426:         DMPlexGlobalToNaturalEnd(dm, originalv, v);
427:         PetscObjectGetName((PetscObject) originalv, &vecname);
428:         PetscObjectSetName((PetscObject) v, vecname);
429:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
430:     } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
431:   } else {
432:     /* we are viewing a natural DMPlex vec. */
433:     v = originalv;
434:   }
435:   if (ishdf5) {
436: #if defined(PETSC_HAVE_HDF5)
437:     VecView_Plex_HDF5_Native_Internal(v, viewer);
438: #else
439:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
440: #endif
441:   } else if (isvtk) {
442:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
443:   } else {
444:     PetscBool isseq;

446:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
447:     if (isseq) {VecView_Seq(v, viewer);}
448:     else       {VecView_MPI(v, viewer);}
449:   }
450:   if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
451:   return(0);
452: }

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

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

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

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

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

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

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

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

540: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
541: {
542:   PetscSection       coordSection;
543:   Vec                coordinates;
544:   DMLabel            depthLabel;
545:   const char        *name[4];
546:   const PetscScalar *a;
547:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
548:   PetscErrorCode     ierr;

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

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

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

595: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
596: {
597:   DM_Plex          *mesh = (DM_Plex*) dm->data;
598:   DM                cdm;
599:   DMLabel           markers;
600:   PetscSection      coordSection;
601:   Vec               coordinates;
602:   PetscViewerFormat format;
603:   PetscErrorCode    ierr;

606:   DMGetCoordinateDM(dm, &cdm);
607:   DMGetSection(cdm, &coordSection);
608:   DMGetCoordinatesLocal(dm, &coordinates);
609:   PetscViewerGetFormat(viewer, &format);
610:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
611:     const char *name;
612:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
613:     PetscInt    pStart, pEnd, p;
614:     PetscMPIInt rank, size;

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

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

644:       PetscSectionGetDof(mesh->coneSection, p, &dof);
645:       PetscSectionGetOffset(mesh->coneSection, p, &off);
646:       for (c = off; c < off+dof; ++c) {
647:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
648:       }
649:     }
650:     PetscViewerFlush(viewer);
651:     PetscViewerASCIIPopSynchronized(viewer);
652:     PetscSectionGetChart(coordSection, &pStart, NULL);
653:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
654:     DMGetLabel(dm, "marker", &markers);
655:     DMLabelView(markers,viewer);
656:     if (size > 1) {
657:       PetscSF sf;

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

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

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

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

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

784:           if ((point < vStart) || (point >= vEnd)) continue;
785:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
786:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
787:           if (firstPoint < 0) firstPoint = point;
788:         }
789:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
790:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
791:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
792:       }
793:     }
794:     VecGetArray(coordinates, &coords);
795:     for (c = cStart; c < cEnd; ++c) {
796:       double    ccoords[3] = {0.0, 0.0, 0.0};
797:       PetscBool isLabeled  = PETSC_FALSE;
798:       PetscInt *closure    = NULL;
799:       PetscInt  closureSize, dof, d, n = 0;

801:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
802:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
803:       for (p = 0; p < closureSize*2; p += 2) {
804:         const PetscInt point = closure[p];
805:         PetscInt       off;

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

847:         DMPlexGetConeSize(dm, e, &coneSize);
848:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
849:         DMPlexGetCone(dm, e, &cone);
850:         PetscSectionGetDof(coordSection, cone[0], &dof);
851:         PetscSectionGetOffset(coordSection, cone[0], &offA);
852:         PetscSectionGetOffset(coordSection, cone[1], &offB);
853:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
854:         for (d = 0; d < dof; ++d) {
855:           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
856:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
857:         }
858:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
859:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
860:         for (d = 0; d < dof; ++d) {
861:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
862:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
863:         }
864:         color = colors[rank%numColors];
865:         for (l = 0; l < numLabels; ++l) {
866:           PetscInt val;
867:           DMGetLabelValue(dm, names[l], v, &val);
868:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
869:         }
870:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
871:       }
872:       VecRestoreArray(coordinates, &coords);
873:       PetscViewerFlush(viewer);
874:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
875:     }
876:     PetscViewerFlush(viewer);
877:     PetscViewerASCIIPopSynchronized(viewer);
878:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
879:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
880:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
881:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
882:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
883:     PetscFree3(names, colors, lcolors);
884:   } else {
885:     MPI_Comm    comm;
886:     PetscInt   *sizes, *hybsizes;
887:     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
888:     PetscInt    pStart, pEnd, p;
889:     PetscInt    numLabels, l;
890:     const char *name;
891:     PetscMPIInt size;

893:     PetscObjectGetComm((PetscObject)dm,&comm);
894:     MPI_Comm_size(comm, &size);
895:     DMGetDimension(dm, &dim);
896:     DMPlexGetVTKCellHeight(dm, &cellHeight);
897:     PetscObjectGetName((PetscObject) dm, &name);
898:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
899:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
900:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
901:     DMPlexGetDepth(dm, &locDepth);
902:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
903:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);
904:     PetscCalloc2(size,&sizes,size,&hybsizes);
905:     if (depth == 1) {
906:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
907:       pEnd = pEnd - pStart;
908:       pMax[0] -= pStart;
909:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
910:       MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
911:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
912:       for (p = 0; p < size; ++p) {
913:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
914:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
915:       }
916:       PetscViewerASCIIPrintf(viewer, "\n");
917:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
918:       pEnd = pEnd - pStart;
919:       pMax[depth] -= pStart;
920:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
921:       MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
922:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
923:       for (p = 0; p < size; ++p) {
924:         if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
925:         else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
926:       }
927:       PetscViewerASCIIPrintf(viewer, "\n");
928:     } else {
929:       PetscMPIInt rank;
930:       MPI_Comm_rank(comm, &rank);
931:       for (d = 0; d <= dim; d++) {
932:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
933:         pEnd    -= pStart;
934:         pMax[d] -= pStart;
935:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
936:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
937:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
938:         for (p = 0; p < size; ++p) {
939:           if (!rank) {
940:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
941:             else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
942:           }
943:         }
944:         PetscViewerASCIIPrintf(viewer, "\n");
945:       }
946:     }
947:     PetscFree2(sizes,hybsizes);
948:     DMGetNumLabels(dm, &numLabels);
949:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
950:     for (l = 0; l < numLabels; ++l) {
951:       DMLabel         label;
952:       const char     *name;
953:       IS              valueIS;
954:       const PetscInt *values;
955:       PetscInt        numValues, v;

957:       DMGetLabelName(dm, l, &name);
958:       DMGetLabel(dm, name, &label);
959:       DMLabelGetNumValues(label, &numValues);
960:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
961:       DMLabelGetValueIS(label, &valueIS);
962:       ISGetIndices(valueIS, &values);
963:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
964:       for (v = 0; v < numValues; ++v) {
965:         PetscInt size;

967:         DMLabelGetStratumSize(label, values[v], &size);
968:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
969:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
970:       }
971:       PetscViewerASCIIPrintf(viewer, ")\n");
972:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
973:       ISRestoreIndices(valueIS, &values);
974:       ISDestroy(&valueIS);
975:     }
976:     DMGetCoarseDM(dm, &cdm);
977:     if (cdm) {
978:       PetscViewerASCIIPushTab(viewer);
979:       DMPlexView_Ascii(cdm, viewer);
980:       PetscViewerASCIIPopTab(viewer);
981:     }
982:   }
983:   return(0);
984: }

986: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
987: {
988:   PetscDraw          draw;
989:   DM                 cdm;
990:   PetscSection       coordSection;
991:   Vec                coordinates;
992:   const PetscScalar *coords;
993:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
994:   PetscBool          isnull;
995:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
996:   PetscMPIInt        rank;
997:   PetscErrorCode     ierr;

1000:   DMGetCoordinateDim(dm, &dim);
1001:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1002:   DMGetCoordinateDM(dm, &cdm);
1003:   DMGetSection(cdm, &coordSection);
1004:   DMGetCoordinatesLocal(dm, &coordinates);
1005:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1006:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

1008:   PetscViewerDrawGetDraw(viewer, 0, &draw);
1009:   PetscDrawIsNull(draw, &isnull);
1010:   if (isnull) return(0);
1011:   PetscDrawSetTitle(draw, "Mesh");

1013:   VecGetLocalSize(coordinates, &N);
1014:   VecGetArrayRead(coordinates, &coords);
1015:   for (c = 0; c < N; c += dim) {
1016:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1017:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1018:   }
1019:   VecRestoreArrayRead(coordinates, &coords);
1020:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
1021:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
1022:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
1023:   PetscDrawClear(draw);

1025:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
1026:   for (c = cStart; c < cEnd; ++c) {
1027:     PetscScalar *coords = NULL;
1028:     PetscInt     numCoords,coneSize;

1030:     DMPlexGetConeSize(dm, c, &coneSize);
1031:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1032:     switch (coneSize) {
1033:     case 3:
1034:       PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1035:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1036:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1037:                                PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1038:       break;
1039:     case 4:
1040:       PetscDrawRectangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1041:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1042:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1043:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1044:                                 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);
1045:       break;
1046:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1047:     }
1048:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1049:   }
1050:   for (c = cStart; c < cEnd; ++c) {
1051:     PetscScalar *coords = NULL;
1052:     PetscInt     numCoords,coneSize;

1054:     DMPlexGetConeSize(dm, c, &coneSize);
1055:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1056:     switch (coneSize) {
1057:     case 3:
1058:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1059:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1060:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1061:       break;
1062:     case 4:
1063:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
1064:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
1065:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
1066:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
1067:       break;
1068:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
1069:     }
1070:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
1071:   }
1072:   PetscDrawFlush(draw);
1073:   PetscDrawPause(draw);
1074:   PetscDrawSave(draw);
1075:   return(0);
1076: }

1078: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1079: {
1080:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
1081:   PetscErrorCode    ierr;

1086:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
1087:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
1088:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
1089:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
1090:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
1091:   if (iascii) {
1092:     PetscViewerFormat format;
1093:     PetscViewerGetFormat(viewer, &format);
1094:     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1095:       DMPlexView_GLVis(dm, viewer);
1096:     } else {
1097:       DMPlexView_Ascii(dm, viewer);
1098:     }
1099:   } else if (ishdf5) {
1100: #if defined(PETSC_HAVE_HDF5)
1101:     DMPlexView_HDF5_Internal(dm, viewer);
1102: #else
1103:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1104: #endif
1105:   } else if (isvtk) {
1106:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
1107:   } else if (isdraw) {
1108:     DMPlexView_Draw(dm, viewer);
1109:   } else if (isglvis) {
1110:     DMPlexView_GLVis(dm, viewer);
1111:   } else {
1112:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1113:   }
1114:   /* Optionally view the partition */
1115:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1116:   if (flg) {
1117:     Vec ranks;
1118:     DMPlexCreateRankField(dm, &ranks);
1119:     VecView(ranks, viewer);
1120:     VecDestroy(&ranks);
1121:   }
1122:   return(0);
1123: }

1125: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1126: {
1127:   PetscBool      ishdf5;

1133:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
1134:   if (ishdf5) {
1135: #if defined(PETSC_HAVE_HDF5)
1136:     PetscViewerFormat format;
1137:     PetscViewerGetFormat(viewer, &format);
1138:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1139:       DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);
1140:     } else {
1141:       DMPlexLoad_HDF5_Internal(dm, viewer);
1142:     }
1143: #else
1144:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1145: #endif
1146:   } else {
1147:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1148:   }
1149:   return(0);
1150: }

1152: PetscErrorCode DMDestroy_Plex(DM dm)
1153: {
1154:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1158:   PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1159:   PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1160:   if (--mesh->refct > 0) return(0);
1161:   PetscSectionDestroy(&mesh->coneSection);
1162:   PetscFree(mesh->cones);
1163:   PetscFree(mesh->coneOrientations);
1164:   PetscSectionDestroy(&mesh->supportSection);
1165:   PetscSectionDestroy(&mesh->subdomainSection);
1166:   PetscFree(mesh->supports);
1167:   PetscFree(mesh->facesTmp);
1168:   PetscFree(mesh->tetgenOpts);
1169:   PetscFree(mesh->triangleOpts);
1170:   PetscPartitionerDestroy(&mesh->partitioner);
1171:   DMLabelDestroy(&mesh->subpointMap);
1172:   ISDestroy(&mesh->globalVertexNumbers);
1173:   ISDestroy(&mesh->globalCellNumbers);
1174:   PetscSectionDestroy(&mesh->anchorSection);
1175:   ISDestroy(&mesh->anchorIS);
1176:   PetscSectionDestroy(&mesh->parentSection);
1177:   PetscFree(mesh->parents);
1178:   PetscFree(mesh->childIDs);
1179:   PetscSectionDestroy(&mesh->childSection);
1180:   PetscFree(mesh->children);
1181:   DMDestroy(&mesh->referenceTree);
1182:   PetscGridHashDestroy(&mesh->lbox);
1183:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1184:   PetscFree(mesh);
1185:   return(0);
1186: }

1188: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1189: {
1190:   PetscSection           sectionGlobal;
1191:   PetscInt               bs = -1, mbs;
1192:   PetscInt               localSize;
1193:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1194:   PetscErrorCode         ierr;
1195:   MatType                mtype;
1196:   ISLocalToGlobalMapping ltog;

1199:   MatInitializePackage();
1200:   mtype = dm->mattype;
1201:   DMGetGlobalSection(dm, &sectionGlobal);
1202:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1203:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1204:   MatCreate(PetscObjectComm((PetscObject)dm), J);
1205:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1206:   MatSetType(*J, mtype);
1207:   MatSetFromOptions(*J);
1208:   MatGetBlockSize(*J, &mbs);
1209:   if (mbs > 1) bs = mbs;
1210:   PetscStrcmp(mtype, MATSHELL, &isShell);
1211:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
1212:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1213:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1214:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1215:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1216:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1217:   PetscStrcmp(mtype, MATIS, &isMatIS);
1218:   if (!isShell) {
1219:     PetscSection subSection;
1220:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1221:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1222:     PetscInt     pStart, pEnd, p, dof, cdof;

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

1229:       DMGetSection(dm, &section);
1230:       PetscSectionGetStorageSize(section, &size);
1231:       PetscMalloc1(size,&ltogidx);
1232:       DMPlexGetSubdomainSection(dm, &subSection);
1233:     } else {
1234:       DMGetLocalToGlobalMapping(dm,&ltog);
1235:     }
1236:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1237:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1238:       PetscInt bdof;

1240:       PetscSectionGetDof(sectionGlobal, p, &dof);
1241:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1242:       dof  = dof < 0 ? -(dof+1) : dof;
1243:       bdof = cdof && (dof-cdof) ? 1 : dof;
1244:       if (dof) {
1245:         if (bs < 0)          {bs = bdof;}
1246:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1247:       }
1248:       if (isMatIS) {
1249:         PetscInt loff,c,off;
1250:         PetscSectionGetOffset(subSection, p, &loff);
1251:         PetscSectionGetOffset(sectionGlobal, p, &off);
1252:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1253:       }
1254:     }
1255:     /* Must have same blocksize on all procs (some might have no points) */
1256:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1257:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1258:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1259:     else                            {bs = bsMinMax[0];}
1260:     bs = bs < 0 ? 1 : bs;
1261:     if (isMatIS) {
1262:       PetscInt l;
1263:       /* Must reduce indices by blocksize */
1264:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1265:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1266:     }
1267:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1268:     if (isMatIS) {
1269:       ISLocalToGlobalMappingDestroy(&ltog);
1270:     }
1271:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1272:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1273:     PetscFree4(dnz, onz, dnzu, onzu);
1274:   }
1275:   MatSetDM(*J, dm);
1276:   return(0);
1277: }

1279: /*@
1280:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1282:   Not collective

1284:   Input Parameter:
1285: . mesh - The DMPlex

1287:   Output Parameters:
1288: . subsection - The subdomain section

1290:   Level: developer

1292: .seealso:
1293: @*/
1294: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1295: {
1296:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1301:   if (!mesh->subdomainSection) {
1302:     PetscSection section;
1303:     PetscSF      sf;

1305:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1306:     DMGetSection(dm,&section);
1307:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1308:     PetscSFDestroy(&sf);
1309:   }
1310:   *subsection = mesh->subdomainSection;
1311:   return(0);
1312: }

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

1317:   Not collective

1319:   Input Parameter:
1320: . mesh - The DMPlex

1322:   Output Parameters:
1323: + pStart - The first mesh point
1324: - pEnd   - The upper bound for mesh points

1326:   Level: beginner

1328: .seealso: DMPlexCreate(), DMPlexSetChart()
1329: @*/
1330: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1331: {
1332:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1337:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1338:   return(0);
1339: }

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

1344:   Not collective

1346:   Input Parameters:
1347: + mesh - The DMPlex
1348: . pStart - The first mesh point
1349: - pEnd   - The upper bound for mesh points

1351:   Output Parameters:

1353:   Level: beginner

1355: .seealso: DMPlexCreate(), DMPlexGetChart()
1356: @*/
1357: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1358: {
1359:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1364:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1365:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1366:   return(0);
1367: }

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

1372:   Not collective

1374:   Input Parameters:
1375: + mesh - The DMPlex
1376: - p - The point, which must lie in the chart set with DMPlexSetChart()

1378:   Output Parameter:
1379: . size - The cone size for point p

1381:   Level: beginner

1383: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1384: @*/
1385: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1386: {
1387:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1393:   PetscSectionGetDof(mesh->coneSection, p, size);
1394:   return(0);
1395: }

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

1400:   Not collective

1402:   Input Parameters:
1403: + mesh - The DMPlex
1404: . p - The point, which must lie in the chart set with DMPlexSetChart()
1405: - size - The cone size for point p

1407:   Output Parameter:

1409:   Note:
1410:   This should be called after DMPlexSetChart().

1412:   Level: beginner

1414: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1415: @*/
1416: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1417: {
1418:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1425:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1426:   return(0);
1427: }

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

1432:   Not collective

1434:   Input Parameters:
1435: + mesh - The DMPlex
1436: . p - The point, which must lie in the chart set with DMPlexSetChart()
1437: - size - The additional cone size for point p

1439:   Output Parameter:

1441:   Note:
1442:   This should be called after DMPlexSetChart().

1444:   Level: beginner

1446: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1447: @*/
1448: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1449: {
1450:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1451:   PetscInt       csize;

1456:   PetscSectionAddDof(mesh->coneSection, p, size);
1457:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1459:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1460:   return(0);
1461: }

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

1466:   Not collective

1468:   Input Parameters:
1469: + mesh - The DMPlex
1470: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1475:   Level: beginner

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

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

1483: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1484: @*/
1485: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1486: {
1487:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1488:   PetscInt       off;

1494:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1495:   *cone = &mesh->cones[off];
1496:   return(0);
1497: }

1499: /*@
1500:   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

1502:   Not collective

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

1509:   Output Parameter:

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

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

1516:   Level: beginner

1518: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
1519: @*/
1520: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1521: {
1522:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1523:   PetscInt       pStart, pEnd;
1524:   PetscInt       dof, off, c;

1529:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1530:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1532:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1533:   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);
1534:   for (c = 0; c < dof; ++c) {
1535:     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);
1536:     mesh->cones[off+c] = cone[c];
1537:   }
1538:   return(0);
1539: }

1541: /*@C
1542:   DMPlexGetConeOrientation - Return the orientations on the 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()

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

1556:   Level: beginner

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

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

1564: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1565: @*/
1566: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1567: {
1568:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1569:   PetscInt       off;

1574: #if defined(PETSC_USE_DEBUG)
1575:   {
1576:     PetscInt dof;
1577:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1579:   }
1580: #endif
1581:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1583:   *coneOrientation = &mesh->coneOrientations[off];
1584:   return(0);
1585: }

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

1590:   Not collective

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

1600:   Output Parameter:

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

1605:   Level: beginner

1607: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1608: @*/
1609: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1610: {
1611:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1612:   PetscInt       pStart, pEnd;
1613:   PetscInt       dof, off, c;

1618:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1619:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1621:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1622:   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);
1623:   for (c = 0; c < dof; ++c) {
1624:     PetscInt cdof, o = coneOrientation[c];

1626:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1627:     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);
1628:     mesh->coneOrientations[off+c] = o;
1629:   }
1630:   return(0);
1631: }

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

1636:   Not collective

1638:   Input Parameters:
1639: + mesh - The DMPlex
1640: . p - The point, which must lie in the chart set with DMPlexSetChart()
1641: . conePos - The local index in the cone where the point should be put
1642: - conePoint - The mesh point to insert

1644:   Level: beginner

1646: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1647: @*/
1648: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1649: {
1650:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1651:   PetscInt       pStart, pEnd;
1652:   PetscInt       dof, off;

1657:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1658:   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);
1659:   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);
1660:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1661:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1662:   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);
1663:   mesh->cones[off+conePos] = conePoint;
1664:   return(0);
1665: }

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

1670:   Not collective

1672:   Input Parameters:
1673: + mesh - The DMPlex
1674: . p - The point, which must lie in the chart set with DMPlexSetChart()
1675: . conePos - The local index in the cone where the point should be put
1676: - coneOrientation - The point orientation to insert

1678:   Level: beginner

1680: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1681: @*/
1682: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1683: {
1684:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1685:   PetscInt       pStart, pEnd;
1686:   PetscInt       dof, off;

1691:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1692:   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);
1693:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1694:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1695:   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);
1696:   mesh->coneOrientations[off+conePos] = coneOrientation;
1697:   return(0);
1698: }

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

1703:   Not collective

1705:   Input Parameters:
1706: + mesh - The DMPlex
1707: - p - The point, which must lie in the chart set with DMPlexSetChart()

1709:   Output Parameter:
1710: . size - The support size for point p

1712:   Level: beginner

1714: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1715: @*/
1716: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1717: {
1718:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1724:   PetscSectionGetDof(mesh->supportSection, p, size);
1725:   return(0);
1726: }

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

1731:   Not collective

1733:   Input Parameters:
1734: + mesh - The DMPlex
1735: . p - The point, which must lie in the chart set with DMPlexSetChart()
1736: - size - The support size for point p

1738:   Output Parameter:

1740:   Note:
1741:   This should be called after DMPlexSetChart().

1743:   Level: beginner

1745: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1746: @*/
1747: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1748: {
1749:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1756:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1757:   return(0);
1758: }

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

1763:   Not collective

1765:   Input Parameters:
1766: + mesh - The DMPlex
1767: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1772:   Level: beginner

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

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

1780: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1781: @*/
1782: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1783: {
1784:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1785:   PetscInt       off;

1791:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1792:   *support = &mesh->supports[off];
1793:   return(0);
1794: }

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

1799:   Not collective

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

1806:   Output Parameter:

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

1811:   Level: beginner

1813: .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1814: @*/
1815: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1816: {
1817:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1818:   PetscInt       pStart, pEnd;
1819:   PetscInt       dof, off, c;

1824:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1825:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1827:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1828:   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);
1829:   for (c = 0; c < dof; ++c) {
1830:     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);
1831:     mesh->supports[off+c] = support[c];
1832:   }
1833:   return(0);
1834: }

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

1839:   Not collective

1841:   Input Parameters:
1842: + mesh - The DMPlex
1843: . p - The point, which must lie in the chart set with DMPlexSetChart()
1844: . supportPos - The local index in the cone where the point should be put
1845: - supportPoint - The mesh point to insert

1847:   Level: beginner

1849: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1850: @*/
1851: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1852: {
1853:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1854:   PetscInt       pStart, pEnd;
1855:   PetscInt       dof, off;

1860:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1861:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1862:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1863:   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);
1864:   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);
1865:   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);
1866:   mesh->supports[off+supportPos] = supportPoint;
1867:   return(0);
1868: }

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

1873:   Not collective

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

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

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

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

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

1894:   Level: beginner

1896: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1897: @*/
1898: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1899: {
1900:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1901:   PetscInt       *closure, *fifo;
1902:   const PetscInt *tmp = NULL, *tmpO = NULL;
1903:   PetscInt        tmpSize, t;
1904:   PetscInt        depth       = 0, maxSize;
1905:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1906:   PetscErrorCode  ierr;

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

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

1956:     closure[closureSize]   = cp;
1957:     closure[closureSize+1] = co;
1958:     fifo[fifoSize]         = cp;
1959:     fifo[fifoSize+1]       = co;
1960:   }
1961:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1962:   while (fifoSize - fifoStart) {
1963:     const PetscInt q   = fifo[fifoStart];
1964:     const PetscInt o   = fifo[fifoStart+1];
1965:     const PetscInt rev = o >= 0 ? 0 : 1;
1966:     const PetscInt off = rev ? -(o+1) : o;

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

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

2013: /*@C
2014:   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

2016:   Not collective

2018:   Input Parameters:
2019: + mesh - The DMPlex
2020: . p - The point, which must lie in the chart set with DMPlexSetChart()
2021: . orientation - The orientation of the point
2022: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2023: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

2038:   Level: beginner

2040: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2041: @*/
2042: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2043: {
2044:   DM_Plex        *mesh = (DM_Plex*) dm->data;
2045:   PetscInt       *closure, *fifo;
2046:   const PetscInt *tmp = NULL, *tmpO = NULL;
2047:   PetscInt        tmpSize, t;
2048:   PetscInt        depth       = 0, maxSize;
2049:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2050:   PetscErrorCode  ierr;

2054:   DMPlexGetDepth(dm, &depth);
2055:   /* This is only 1-level */
2056:   if (useCone) {
2057:     DMPlexGetConeSize(dm, p, &tmpSize);
2058:     DMPlexGetCone(dm, p, &tmp);
2059:     DMPlexGetConeOrientation(dm, p, &tmpO);
2060:   } else {
2061:     DMPlexGetSupportSize(dm, p, &tmpSize);
2062:     DMPlexGetSupport(dm, p, &tmp);
2063:   }
2064:   if (depth == 1) {
2065:     if (*points) {
2066:       closure = *points;
2067:     } else {
2068:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2069:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2070:     }
2071:     closure[0] = p; closure[1] = ornt;
2072:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2073:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2074:       closure[closureSize]   = tmp[i];
2075:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2076:     }
2077:     if (numPoints) *numPoints = closureSize/2;
2078:     if (points)    *points    = closure;
2079:     return(0);
2080:   }
2081:   {
2082:     PetscInt c, coneSeries, s,supportSeries;

2084:     c = mesh->maxConeSize;
2085:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2086:     s = mesh->maxSupportSize;
2087:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2088:     maxSize = 2*PetscMax(coneSeries,supportSeries);
2089:   }
2090:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
2091:   if (*points) {
2092:     closure = *points;
2093:   } else {
2094:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
2095:   }
2096:   closure[0] = p; closure[1] = ornt;
2097:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2098:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2099:     const PetscInt cp = tmp[i];
2100:     PetscInt       co = tmpO ? tmpO[i] : 0;

2102:     if (ornt < 0) {
2103:       PetscInt childSize, coff;
2104:       DMPlexGetConeSize(dm, cp, &childSize);
2105:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2106:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2107:     }
2108:     closure[closureSize]   = cp;
2109:     closure[closureSize+1] = co;
2110:     fifo[fifoSize]         = cp;
2111:     fifo[fifoSize+1]       = co;
2112:   }
2113:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2114:   while (fifoSize - fifoStart) {
2115:     const PetscInt q   = fifo[fifoStart];
2116:     const PetscInt o   = fifo[fifoStart+1];
2117:     const PetscInt rev = o >= 0 ? 0 : 1;
2118:     const PetscInt off = rev ? -(o+1) : o;

2120:     if (useCone) {
2121:       DMPlexGetConeSize(dm, q, &tmpSize);
2122:       DMPlexGetCone(dm, q, &tmp);
2123:       DMPlexGetConeOrientation(dm, q, &tmpO);
2124:     } else {
2125:       DMPlexGetSupportSize(dm, q, &tmpSize);
2126:       DMPlexGetSupport(dm, q, &tmp);
2127:       tmpO = NULL;
2128:     }
2129:     for (t = 0; t < tmpSize; ++t) {
2130:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2131:       const PetscInt cp = tmp[i];
2132:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2133:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2134:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2135:       PetscInt       co = tmpO ? tmpO[i] : 0;
2136:       PetscInt       c;

2138:       if (rev) {
2139:         PetscInt childSize, coff;
2140:         DMPlexGetConeSize(dm, cp, &childSize);
2141:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2142:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2143:       }
2144:       /* Check for duplicate */
2145:       for (c = 0; c < closureSize; c += 2) {
2146:         if (closure[c] == cp) break;
2147:       }
2148:       if (c == closureSize) {
2149:         closure[closureSize]   = cp;
2150:         closure[closureSize+1] = co;
2151:         fifo[fifoSize]         = cp;
2152:         fifo[fifoSize+1]       = co;
2153:         closureSize           += 2;
2154:         fifoSize              += 2;
2155:       }
2156:     }
2157:     fifoStart += 2;
2158:   }
2159:   if (numPoints) *numPoints = closureSize/2;
2160:   if (points)    *points    = closure;
2161:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2162:   return(0);
2163: }

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

2168:   Not collective

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

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

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

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

2186:   Level: beginner

2188: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2189: @*/
2190: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2191: {

2198:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2199:   if (numPoints) *numPoints = 0;
2200:   return(0);
2201: }

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

2206:   Not collective

2208:   Input Parameter:
2209: . mesh - The DMPlex

2211:   Output Parameters:
2212: + maxConeSize - The maximum number of in-edges
2213: - maxSupportSize - The maximum number of out-edges

2215:   Level: beginner

2217: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2218: @*/
2219: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2220: {
2221:   DM_Plex *mesh = (DM_Plex*) dm->data;

2225:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2226:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2227:   return(0);
2228: }

2230: PetscErrorCode DMSetUp_Plex(DM dm)
2231: {
2232:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2233:   PetscInt       size;

2238:   PetscSectionSetUp(mesh->coneSection);
2239:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2240:   PetscMalloc1(size, &mesh->cones);
2241:   PetscCalloc1(size, &mesh->coneOrientations);
2242:   if (mesh->maxSupportSize) {
2243:     PetscSectionSetUp(mesh->supportSection);
2244:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2245:     PetscMalloc1(size, &mesh->supports);
2246:   }
2247:   return(0);
2248: }

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

2255:   if (subdm) {DMClone(dm, subdm);}
2256:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2257:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2258:   if (dm->useNatural && dm->sfMigration) {
2259:     PetscSF        sfMigrationInv,sfNatural;
2260:     PetscSection   section, sectionSeq;

2262:     (*subdm)->sfMigration = dm->sfMigration;
2263:     PetscObjectReference((PetscObject) dm->sfMigration);
2264:     DMGetSection((*subdm), &section);
2265:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2266:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
2267:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2269:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2270:     (*subdm)->sfNatural = sfNatural;
2271:     PetscSectionDestroy(&sectionSeq);
2272:     PetscSFDestroy(&sfMigrationInv);
2273:   }
2274:   return(0);
2275: }

2277: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2278: {
2280:   PetscInt       i = 0;

2283:   if (superdm) {DMClone(dms[0], superdm);}
2284:   DMCreateSuperDM_Section_Private(dms, len, is, superdm);
2285:   (*superdm)->useNatural = PETSC_FALSE;
2286:   for (i = 0; i < len; i++){
2287:     if (dms[i]->useNatural && dms[i]->sfMigration) {
2288:       PetscSF        sfMigrationInv,sfNatural;
2289:       PetscSection   section, sectionSeq;

2291:       (*superdm)->sfMigration = dms[i]->sfMigration;
2292:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
2293:       (*superdm)->useNatural = PETSC_TRUE;
2294:       DMGetSection((*superdm), &section);
2295:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2296:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
2297:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);

2299:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2300:       (*superdm)->sfNatural = sfNatural;
2301:       PetscSectionDestroy(&sectionSeq);
2302:       PetscSFDestroy(&sfMigrationInv);
2303:       break;
2304:     }
2305:   }
2306:   return(0);
2307: }

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

2312:   Not collective

2314:   Input Parameter:
2315: . mesh - The DMPlex

2317:   Output Parameter:

2319:   Note:
2320:   This should be called after all calls to DMPlexSetCone()

2322:   Level: beginner

2324: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2325: @*/
2326: PetscErrorCode DMPlexSymmetrize(DM dm)
2327: {
2328:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2329:   PetscInt      *offsets;
2330:   PetscInt       supportSize;
2331:   PetscInt       pStart, pEnd, p;

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

2342:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2343:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2344:     for (c = off; c < off+dof; ++c) {
2345:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2346:     }
2347:   }
2348:   for (p = pStart; p < pEnd; ++p) {
2349:     PetscInt dof;

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

2353:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2354:   }
2355:   PetscSectionSetUp(mesh->supportSection);
2356:   /* Calculate supports */
2357:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2358:   PetscMalloc1(supportSize, &mesh->supports);
2359:   PetscCalloc1(pEnd - pStart, &offsets);
2360:   for (p = pStart; p < pEnd; ++p) {
2361:     PetscInt dof, off, c;

2363:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2364:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2365:     for (c = off; c < off+dof; ++c) {
2366:       const PetscInt q = mesh->cones[c];
2367:       PetscInt       offS;

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

2371:       mesh->supports[offS+offsets[q]] = p;
2372:       ++offsets[q];
2373:     }
2374:   }
2375:   PetscFree(offsets);
2376:   return(0);
2377: }

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

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

2387:   Collective on dm

2389:   Input Parameter:
2390: . mesh - The DMPlex

2392:   Output Parameter:

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

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

2402:   Level: beginner

2404: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2405: @*/
2406: PetscErrorCode DMPlexStratify(DM dm)
2407: {
2408:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2409:   DMLabel        label;
2410:   PetscInt       pStart, pEnd, p;
2411:   PetscInt       numRoots = 0, numLeaves = 0;
2412:   PetscInt       cMax, fMax, eMax, vMax;

2417:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2418:   /* Calculate depth */
2419:   DMPlexGetChart(dm, &pStart, &pEnd);
2420:   DMCreateLabel(dm, "depth");
2421:   DMPlexGetDepthLabel(dm, &label);
2422:   /* Initialize roots and count leaves */
2423:   for (p = pStart; p < pEnd; ++p) {
2424:     PetscInt coneSize, supportSize;

2426:     DMPlexGetConeSize(dm, p, &coneSize);
2427:     DMPlexGetSupportSize(dm, p, &supportSize);
2428:     if (!coneSize && supportSize) {
2429:       ++numRoots;
2430:       DMLabelSetValue(label, p, 0);
2431:     } else if (!supportSize && coneSize) {
2432:       ++numLeaves;
2433:     } else if (!supportSize && !coneSize) {
2434:       /* Isolated points */
2435:       DMLabelSetValue(label, p, 0);
2436:     }
2437:   }
2438:   if (numRoots + numLeaves == (pEnd - pStart)) {
2439:     for (p = pStart; p < pEnd; ++p) {
2440:       PetscInt coneSize, supportSize;

2442:       DMPlexGetConeSize(dm, p, &coneSize);
2443:       DMPlexGetSupportSize(dm, p, &supportSize);
2444:       if (!supportSize && coneSize) {
2445:         DMLabelSetValue(label, p, 1);
2446:       }
2447:     }
2448:   } else {
2449:     IS       pointIS;
2450:     PetscInt numPoints = 0, level = 0;

2452:     DMLabelGetStratumIS(label, level, &pointIS);
2453:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2454:     while (numPoints) {
2455:       const PetscInt *points;
2456:       const PetscInt  newLevel = level+1;

2458:       ISGetIndices(pointIS, &points);
2459:       for (p = 0; p < numPoints; ++p) {
2460:         const PetscInt  point = points[p];
2461:         const PetscInt *support;
2462:         PetscInt        supportSize, s;

2464:         DMPlexGetSupportSize(dm, point, &supportSize);
2465:         DMPlexGetSupport(dm, point, &support);
2466:         for (s = 0; s < supportSize; ++s) {
2467:           DMLabelSetValue(label, support[s], newLevel);
2468:         }
2469:       }
2470:       ISRestoreIndices(pointIS, &points);
2471:       ++level;
2472:       ISDestroy(&pointIS);
2473:       DMLabelGetStratumIS(label, level, &pointIS);
2474:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2475:       else         {numPoints = 0;}
2476:     }
2477:     ISDestroy(&pointIS);
2478:   }
2479:   { /* just in case there is an empty process */
2480:     PetscInt numValues, maxValues = 0, v;

2482:     DMLabelGetNumValues(label,&numValues);
2483:     for (v = 0; v < numValues; v++) {
2484:       IS pointIS;

2486:       DMLabelGetStratumIS(label, v, &pointIS);
2487:       if (pointIS) {
2488:         PetscInt  min, max, numPoints;
2489:         PetscInt  start;
2490:         PetscBool contig;

2492:         ISGetLocalSize(pointIS, &numPoints);
2493:         ISGetMinMax(pointIS, &min, &max);
2494:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2495:         if (start == 0 && contig) {
2496:           ISDestroy(&pointIS);
2497:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2498:           DMLabelSetStratumIS(label, v, pointIS);
2499:         }
2500:       }
2501:       ISDestroy(&pointIS);
2502:     }
2503:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2504:     for (v = numValues; v < maxValues; v++) {
2505:       DMLabelAddStratum(label,v);
2506:     }
2507:   }
2508:   DMLabelGetState(label, &mesh->depthState);

2510:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
2511:   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2512:     DMLabel  dimLabel;
2513:     PetscInt dim;

2515:     DMGetDimension(dm, &dim);
2516:     DMGetLabel(dm, "dim", &dimLabel);
2517:     if (!dimLabel) {
2518:       DMCreateLabel(dm, "dim");
2519:       DMGetLabel(dm, "dim", &dimLabel);
2520:     }
2521:     if (cMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);}
2522:     if (fMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);}
2523:     if (eMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);}
2524:     if (vMax >= 0) {DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);}
2525:   }
2526:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2527:   return(0);
2528: }

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

2533:   Not Collective

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

2540:   Output Parameters:
2541: + numCoveredPoints - The number of points in the join
2542: - coveredPoints - The points in the join

2544:   Level: intermediate

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

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

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

2554: .keywords: mesh
2555: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2556: @*/
2557: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2558: {
2559:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2560:   PetscInt      *join[2];
2561:   PetscInt       joinSize, i = 0;
2562:   PetscInt       dof, off, p, c, m;

2570:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2571:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2572:   /* Copy in support of first point */
2573:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2574:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2575:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2576:     join[i][joinSize] = mesh->supports[off+joinSize];
2577:   }
2578:   /* Check each successive support */
2579:   for (p = 1; p < numPoints; ++p) {
2580:     PetscInt newJoinSize = 0;

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

2587:       for (m = 0; m < joinSize; ++m) {
2588:         if (point == join[i][m]) {
2589:           join[1-i][newJoinSize++] = point;
2590:           break;
2591:         }
2592:       }
2593:     }
2594:     joinSize = newJoinSize;
2595:     i        = 1-i;
2596:   }
2597:   *numCoveredPoints = joinSize;
2598:   *coveredPoints    = join[i];
2599:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2600:   return(0);
2601: }

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

2606:   Not Collective

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

2613:   Output Parameters:
2614: + numCoveredPoints - The number of points in the join
2615: - coveredPoints - The points in the join

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

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

2623:   Level: intermediate

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

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

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

2645:   Not Collective

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

2652:   Output Parameters:
2653: + numCoveredPoints - The number of points in the join
2654: - coveredPoints - The points in the join

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

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

2662:   Level: intermediate

2664: .keywords: mesh
2665: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2666: @*/
2667: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2668: {
2669:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2670:   PetscInt      *offsets, **closures;
2671:   PetscInt      *join[2];
2672:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2673:   PetscInt       p, d, c, m, ms;


2682:   DMPlexGetDepth(dm, &depth);
2683:   PetscCalloc1(numPoints, &closures);
2684:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2685:   ms      = mesh->maxSupportSize;
2686:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2687:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2688:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

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

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

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

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

2713:     /* Copy in support of first point */
2714:     dof = offsets[d+1] - offsets[d];
2715:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2716:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2717:     }
2718:     /* Check each successive cone */
2719:     for (p = 1; p < numPoints && joinSize; ++p) {
2720:       PetscInt newJoinSize = 0;

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

2726:         for (m = 0; m < joinSize; ++m) {
2727:           if (point == join[i][m]) {
2728:             join[1-i][newJoinSize++] = point;
2729:             break;
2730:           }
2731:         }
2732:       }
2733:       joinSize = newJoinSize;
2734:       i        = 1-i;
2735:     }
2736:     if (joinSize) break;
2737:   }
2738:   *numCoveredPoints = joinSize;
2739:   *coveredPoints    = join[i];
2740:   for (p = 0; p < numPoints; ++p) {
2741:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2742:   }
2743:   PetscFree(closures);
2744:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2745:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2746:   return(0);
2747: }

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

2752:   Not Collective

2754:   Input Parameters:
2755: + dm - The DMPlex object
2756: . numPoints - The number of input points for the meet
2757: - points - The input points

2759:   Output Parameters:
2760: + numCoveredPoints - The number of points in the meet
2761: - coveredPoints - The points in the meet

2763:   Level: intermediate

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

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

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

2773: .keywords: mesh
2774: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2775: @*/
2776: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2777: {
2778:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2779:   PetscInt      *meet[2];
2780:   PetscInt       meetSize, i = 0;
2781:   PetscInt       dof, off, p, c, m;

2789:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
2790:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
2791:   /* Copy in cone of first point */
2792:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2793:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2794:   for (meetSize = 0; meetSize < dof; ++meetSize) {
2795:     meet[i][meetSize] = mesh->cones[off+meetSize];
2796:   }
2797:   /* Check each successive cone */
2798:   for (p = 1; p < numPoints; ++p) {
2799:     PetscInt newMeetSize = 0;

2801:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2802:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2803:     for (c = 0; c < dof; ++c) {
2804:       const PetscInt point = mesh->cones[off+c];

2806:       for (m = 0; m < meetSize; ++m) {
2807:         if (point == meet[i][m]) {
2808:           meet[1-i][newMeetSize++] = point;
2809:           break;
2810:         }
2811:       }
2812:     }
2813:     meetSize = newMeetSize;
2814:     i        = 1-i;
2815:   }
2816:   *numCoveringPoints = meetSize;
2817:   *coveringPoints    = meet[i];
2818:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2819:   return(0);
2820: }

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

2825:   Not Collective

2827:   Input Parameters:
2828: + dm - The DMPlex object
2829: . numPoints - The number of input points for the meet
2830: - points - The input points

2832:   Output Parameters:
2833: + numCoveredPoints - The number of points in the meet
2834: - coveredPoints - The points in the meet

2836:   Level: intermediate

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

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

2844: .keywords: mesh
2845: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2846: @*/
2847: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2848: {

2856:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2857:   if (numCoveredPoints) *numCoveredPoints = 0;
2858:   return(0);
2859: }

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

2864:   Not Collective

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

2871:   Output Parameters:
2872: + numCoveredPoints - The number of points in the meet
2873: - coveredPoints - The points in the meet

2875:   Level: intermediate

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

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

2883: .keywords: mesh
2884: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2885: @*/
2886: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2887: {
2888:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2889:   PetscInt      *offsets, **closures;
2890:   PetscInt      *meet[2];
2891:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2892:   PetscInt       p, h, c, m, mc;


2901:   DMPlexGetDepth(dm, &height);
2902:   PetscMalloc1(numPoints, &closures);
2903:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2904:   mc      = mesh->maxConeSize;
2905:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2906:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
2907:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

2909:   for (p = 0; p < numPoints; ++p) {
2910:     PetscInt closureSize;

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

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

2918:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2919:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2920:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2921:           offsets[p*(height+2)+h+1] = i;
2922:           break;
2923:         }
2924:       }
2925:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2926:     }
2927:     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);
2928:   }
2929:   for (h = 0; h < height+1; ++h) {
2930:     PetscInt dof;

2932:     /* Copy in cone of first point */
2933:     dof = offsets[h+1] - offsets[h];
2934:     for (meetSize = 0; meetSize < dof; ++meetSize) {
2935:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2936:     }
2937:     /* Check each successive cone */
2938:     for (p = 1; p < numPoints && meetSize; ++p) {
2939:       PetscInt newMeetSize = 0;

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

2945:         for (m = 0; m < meetSize; ++m) {
2946:           if (point == meet[i][m]) {
2947:             meet[1-i][newMeetSize++] = point;
2948:             break;
2949:           }
2950:         }
2951:       }
2952:       meetSize = newMeetSize;
2953:       i        = 1-i;
2954:     }
2955:     if (meetSize) break;
2956:   }
2957:   *numCoveredPoints = meetSize;
2958:   *coveredPoints    = meet[i];
2959:   for (p = 0; p < numPoints; ++p) {
2960:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2961:   }
2962:   PetscFree(closures);
2963:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2964:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2965:   return(0);
2966: }

2968: /*@C
2969:   DMPlexEqual - Determine if two DMs have the same topology

2971:   Not Collective

2973:   Input Parameters:
2974: + dmA - A DMPlex object
2975: - dmB - A DMPlex object

2977:   Output Parameters:
2978: . equal - PETSC_TRUE if the topologies are identical

2980:   Level: intermediate

2982:   Notes:
2983:   We are not solving graph isomorphism, so we do not permutation.

2985: .keywords: mesh
2986: .seealso: DMPlexGetCone()
2987: @*/
2988: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2989: {
2990:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


2998:   *equal = PETSC_FALSE;
2999:   DMPlexGetDepth(dmA, &depth);
3000:   DMPlexGetDepth(dmB, &depthB);
3001:   if (depth != depthB) return(0);
3002:   DMPlexGetChart(dmA, &pStart,  &pEnd);
3003:   DMPlexGetChart(dmB, &pStartB, &pEndB);
3004:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
3005:   for (p = pStart; p < pEnd; ++p) {
3006:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3007:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

3009:     DMPlexGetConeSize(dmA, p, &coneSize);
3010:     DMPlexGetCone(dmA, p, &cone);
3011:     DMPlexGetConeOrientation(dmA, p, &ornt);
3012:     DMPlexGetConeSize(dmB, p, &coneSizeB);
3013:     DMPlexGetCone(dmB, p, &coneB);
3014:     DMPlexGetConeOrientation(dmB, p, &orntB);
3015:     if (coneSize != coneSizeB) return(0);
3016:     for (c = 0; c < coneSize; ++c) {
3017:       if (cone[c] != coneB[c]) return(0);
3018:       if (ornt[c] != orntB[c]) return(0);
3019:     }
3020:     DMPlexGetSupportSize(dmA, p, &supportSize);
3021:     DMPlexGetSupport(dmA, p, &support);
3022:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
3023:     DMPlexGetSupport(dmB, p, &supportB);
3024:     if (supportSize != supportSizeB) return(0);
3025:     for (s = 0; s < supportSize; ++s) {
3026:       if (support[s] != supportB[s]) return(0);
3027:     }
3028:   }
3029:   *equal = PETSC_TRUE;
3030:   return(0);
3031: }

3033: /*@C
3034:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

3036:   Not Collective

3038:   Input Parameters:
3039: + dm         - The DMPlex
3040: . cellDim    - The cell dimension
3041: - numCorners - The number of vertices on a cell

3043:   Output Parameters:
3044: . numFaceVertices - The number of vertices on a face

3046:   Level: developer

3048:   Notes:
3049:   Of course this can only work for a restricted set of symmetric shapes

3051: .seealso: DMPlexGetCone()
3052: @*/
3053: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3054: {
3055:   MPI_Comm       comm;

3059:   PetscObjectGetComm((PetscObject)dm,&comm);
3061:   switch (cellDim) {
3062:   case 0:
3063:     *numFaceVertices = 0;
3064:     break;
3065:   case 1:
3066:     *numFaceVertices = 1;
3067:     break;
3068:   case 2:
3069:     switch (numCorners) {
3070:     case 3: /* triangle */
3071:       *numFaceVertices = 2; /* Edge has 2 vertices */
3072:       break;
3073:     case 4: /* quadrilateral */
3074:       *numFaceVertices = 2; /* Edge has 2 vertices */
3075:       break;
3076:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3077:       *numFaceVertices = 3; /* Edge has 3 vertices */
3078:       break;
3079:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3080:       *numFaceVertices = 3; /* Edge has 3 vertices */
3081:       break;
3082:     default:
3083:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3084:     }
3085:     break;
3086:   case 3:
3087:     switch (numCorners) {
3088:     case 4: /* tetradehdron */
3089:       *numFaceVertices = 3; /* Face has 3 vertices */
3090:       break;
3091:     case 6: /* tet cohesive cells */
3092:       *numFaceVertices = 4; /* Face has 4 vertices */
3093:       break;
3094:     case 8: /* hexahedron */
3095:       *numFaceVertices = 4; /* Face has 4 vertices */
3096:       break;
3097:     case 9: /* tet cohesive Lagrange cells */
3098:       *numFaceVertices = 6; /* Face has 6 vertices */
3099:       break;
3100:     case 10: /* quadratic tetrahedron */
3101:       *numFaceVertices = 6; /* Face has 6 vertices */
3102:       break;
3103:     case 12: /* hex cohesive Lagrange cells */
3104:       *numFaceVertices = 6; /* Face has 6 vertices */
3105:       break;
3106:     case 18: /* quadratic tet cohesive Lagrange cells */
3107:       *numFaceVertices = 6; /* Face has 6 vertices */
3108:       break;
3109:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3110:       *numFaceVertices = 9; /* Face has 9 vertices */
3111:       break;
3112:     default:
3113:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3114:     }
3115:     break;
3116:   default:
3117:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3118:   }
3119:   return(0);
3120: }

3122: /*@
3123:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

3125:   Not Collective

3127:   Input Parameter:
3128: . dm    - The DMPlex object

3130:   Output Parameter:
3131: . depthLabel - The DMLabel recording point depth

3133:   Level: developer

3135: .keywords: mesh, points
3136: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3137: @*/
3138: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3139: {

3145:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3146:   *depthLabel = dm->depthLabel;
3147:   return(0);
3148: }

3150: /*@
3151:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

3153:   Not Collective

3155:   Input Parameter:
3156: . dm    - The DMPlex object

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

3161:   Level: developer

3163: .keywords: mesh, points
3164: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3165: @*/
3166: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3167: {
3168:   DMLabel        label;
3169:   PetscInt       d = 0;

3175:   DMPlexGetDepthLabel(dm, &label);
3176:   if (label) {DMLabelGetNumValues(label, &d);}
3177:   *depth = d-1;
3178:   return(0);
3179: }

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

3184:   Not Collective

3186:   Input Parameters:
3187: + dm           - The DMPlex object
3188: - stratumValue - The requested depth

3190:   Output Parameters:
3191: + start - The first point at this depth
3192: - end   - One beyond the last point at this depth

3194:   Level: developer

3196: .keywords: mesh, points
3197: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3198: @*/
3199: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3200: {
3201:   DMLabel        label;
3202:   PetscInt       pStart, pEnd;

3209:   DMPlexGetChart(dm, &pStart, &pEnd);
3210:   if (pStart == pEnd) return(0);
3211:   if (stratumValue < 0) {
3212:     if (start) *start = pStart;
3213:     if (end)   *end   = pEnd;
3214:     return(0);
3215:   }
3216:   DMPlexGetDepthLabel(dm, &label);
3217:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3218:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3219:   return(0);
3220: }

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

3225:   Not Collective

3227:   Input Parameters:
3228: + dm           - The DMPlex object
3229: - stratumValue - The requested height

3231:   Output Parameters:
3232: + start - The first point at this height
3233: - end   - One beyond the last point at this height

3235:   Level: developer

3237: .keywords: mesh, points
3238: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3239: @*/
3240: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3241: {
3242:   DMLabel        label;
3243:   PetscInt       depth, pStart, pEnd;

3250:   DMPlexGetChart(dm, &pStart, &pEnd);
3251:   if (pStart == pEnd) return(0);
3252:   if (stratumValue < 0) {
3253:     if (start) *start = pStart;
3254:     if (end)   *end   = pEnd;
3255:     return(0);
3256:   }
3257:   DMPlexGetDepthLabel(dm, &label);
3258:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3259:   DMLabelGetNumValues(label, &depth);
3260:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3261:   return(0);
3262: }

3264: /* Set the number of dof on each point and separate by fields */
3265: static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3266: {
3267:   PetscInt      *pMax;
3268:   PetscInt       depth, cellHeight, pStart = 0, pEnd = 0;
3269:   PetscInt       Nf, p, d, dep, f;
3270:   PetscBool     *isFE;

3274:   PetscMalloc1(numFields, &isFE);
3275:   DMGetNumFields(dm, &Nf);
3276:   for (f = 0; f < numFields; ++f) {
3277:     PetscObject  obj;
3278:     PetscClassId id;

3280:     isFE[f] = PETSC_FALSE;
3281:     if (f >= Nf) continue;
3282:     DMGetField(dm, f, &obj);
3283:     PetscObjectGetClassId(obj, &id);
3284:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
3285:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3286:   }
3287:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
3288:   if (numFields > 0) {
3289:     PetscSectionSetNumFields(*section, numFields);
3290:     if (numComp) {
3291:       for (f = 0; f < numFields; ++f) {
3292:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
3293:         if (isFE[f]) {
3294:           PetscFE           fe;
3295:           PetscDualSpace    dspace;
3296:           const PetscInt    ***perms;
3297:           const PetscScalar ***flips;
3298:           const PetscInt    *numDof;

3300:           DMGetField(dm,f,(PetscObject *) &fe);
3301:           PetscFEGetDualSpace(fe,&dspace);
3302:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3303:           PetscDualSpaceGetNumDof(dspace,&numDof);
3304:           if (perms || flips) {
3305:             DM               K;
3306:             DMLabel          depthLabel;
3307:             PetscInt         depth, h;
3308:             PetscSectionSym  sym;

3310:             PetscDualSpaceGetDM(dspace,&K);
3311:             DMPlexGetDepthLabel(dm,&depthLabel);
3312:             DMPlexGetDepth(dm,&depth);
3313:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
3314:             for (h = 0; h <= depth; h++) {
3315:               PetscDualSpace    hspace;
3316:               PetscInt          kStart, kEnd;
3317:               PetscInt          kConeSize;
3318:               const PetscInt    **perms0 = NULL;
3319:               const PetscScalar **flips0 = NULL;

3321:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
3322:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
3323:               if (!hspace) continue;
3324:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
3325:               if (perms) perms0 = perms[0];
3326:               if (flips) flips0 = flips[0];
3327:               if (!(perms0 || flips0)) continue;
3328:               DMPlexGetConeSize(K,kStart,&kConeSize);
3329:               PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
3330:             }
3331:             PetscSectionSetFieldSym(*section,f,sym);
3332:             PetscSectionSymDestroy(&sym);
3333:           }
3334:         }
3335:       }
3336:     }
3337:   }
3338:   DMPlexGetChart(dm, &pStart, &pEnd);
3339:   PetscSectionSetChart(*section, pStart, pEnd);
3340:   DMPlexGetDepth(dm, &depth);
3341:   PetscMalloc1(depth+1,&pMax);
3342:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3343:   DMPlexGetVTKCellHeight(dm, &cellHeight);
3344:   for (dep = 0; dep <= depth - cellHeight; ++dep) {
3345:     d    = dim == depth ? dep : (!dep ? 0 : dim);
3346:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3347:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3348:     for (p = pStart; p < pEnd; ++p) {
3349:       PetscInt tot = 0;

3351:       for (f = 0; f < numFields; ++f) {
3352:         if (isFE[f] && p >= pMax[dep]) continue;
3353:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3354:         tot += numDof[f*(dim+1)+d];
3355:       }
3356:       PetscSectionSetDof(*section, p, tot);
3357:     }
3358:   }
3359:   PetscFree(pMax);
3360:   PetscFree(isFE);
3361:   return(0);
3362: }

3364: /* Set the number of dof on each point and separate by fields
3365:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3366: */
3367: static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3368: {
3369:   PetscInt       numFields;
3370:   PetscInt       bc;
3371:   PetscSection   aSec;

3375:   PetscSectionGetNumFields(section, &numFields);
3376:   for (bc = 0; bc < numBC; ++bc) {
3377:     PetscInt        field = 0;
3378:     const PetscInt *comp;
3379:     const PetscInt *idx;
3380:     PetscInt        Nc = -1, n, i;

3382:     if (numFields) field = bcField[bc];
3383:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3384:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3385:     ISGetLocalSize(bcPoints[bc], &n);
3386:     ISGetIndices(bcPoints[bc], &idx);
3387:     for (i = 0; i < n; ++i) {
3388:       const PetscInt p = idx[i];
3389:       PetscInt       numConst;

3391:       if (numFields) {
3392:         PetscSectionGetFieldDof(section, p, field, &numConst);
3393:       } else {
3394:         PetscSectionGetDof(section, p, &numConst);
3395:       }
3396:       /* If Nc < 0, constrain every dof on the point */
3397:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3398:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3399:       PetscSectionAddConstraintDof(section, p, numConst);
3400:     }
3401:     ISRestoreIndices(bcPoints[bc], &idx);
3402:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3403:   }
3404:   DMPlexGetAnchors(dm, &aSec, NULL);
3405:   if (aSec) {
3406:     PetscInt aStart, aEnd, a;

3408:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3409:     for (a = aStart; a < aEnd; a++) {
3410:       PetscInt dof, f;

3412:       PetscSectionGetDof(aSec, a, &dof);
3413:       if (dof) {
3414:         /* if there are point-to-point constraints, then all dofs are constrained */
3415:         PetscSectionGetDof(section, a, &dof);
3416:         PetscSectionSetConstraintDof(section, a, dof);
3417:         for (f = 0; f < numFields; f++) {
3418:           PetscSectionGetFieldDof(section, a, f, &dof);
3419:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3420:         }
3421:       }
3422:     }
3423:   }
3424:   return(0);
3425: }

3427: /* Set the constrained field indices on each point
3428:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3429: */
3430: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3431: {
3432:   PetscSection   aSec;
3433:   PetscInt      *indices;
3434:   PetscInt       numFields, cdof, maxDof = 0, pStart, pEnd, p, bc, f, d;

3438:   PetscSectionGetNumFields(section, &numFields);
3439:   if (!numFields) return(0);
3440:   /* Initialize all field indices to -1 */
3441:   PetscSectionGetChart(section, &pStart, &pEnd);
3442:   for (p = pStart; p < pEnd; ++p) {PetscSectionGetConstraintDof(section, p, &cdof); maxDof = PetscMax(maxDof, cdof);}
3443:   PetscMalloc1(maxDof, &indices);
3444:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3445:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3446:   /* Handle BC constraints */
3447:   for (bc = 0; bc < numBC; ++bc) {
3448:     const PetscInt  field = bcField[bc];
3449:     const PetscInt *comp, *idx;
3450:     PetscInt        Nc = -1, n, i;

3452:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3453:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3454:     ISGetLocalSize(bcPoints[bc], &n);
3455:     ISGetIndices(bcPoints[bc], &idx);
3456:     for (i = 0; i < n; ++i) {
3457:       const PetscInt  p = idx[i];
3458:       const PetscInt *find;
3459:       PetscInt        fdof, fcdof, c;

3461:       PetscSectionGetFieldDof(section, p, field, &fdof);
3462:       if (!fdof) continue;
3463:       if (Nc < 0) {
3464:         for (d = 0; d < fdof; ++d) indices[d] = d;
3465:         fcdof = fdof;
3466:       } else {
3467:         PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3468:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3469:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3470:         for (c = 0; c < Nc; ++c) indices[d++] = comp[c];
3471:         PetscSortRemoveDupsInt(&d, indices);
3472:         for (c = d; c < fcdof; ++c) indices[c] = -1;
3473:         fcdof = d;
3474:       }
3475:       PetscSectionSetFieldConstraintDof(section, p, field, fcdof);
3476:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3477:     }
3478:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3479:     ISRestoreIndices(bcPoints[bc], &idx);
3480:   }
3481:   /* Handle anchors */
3482:   DMPlexGetAnchors(dm, &aSec, NULL);
3483:   if (aSec) {
3484:     PetscInt aStart, aEnd, a;

3486:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3487:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3488:     for (a = aStart; a < aEnd; a++) {
3489:       PetscInt dof, f;

3491:       PetscSectionGetDof(aSec, a, &dof);
3492:       if (dof) {
3493:         /* if there are point-to-point constraints, then all dofs are constrained */
3494:         for (f = 0; f < numFields; f++) {
3495:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3496:         }
3497:       }
3498:     }
3499:   }
3500:   PetscFree(indices);
3501:   return(0);
3502: }

3504: /* Set the constrained indices on each point */
3505: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3506: {
3507:   PetscInt      *indices;
3508:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3512:   PetscSectionGetNumFields(section, &numFields);
3513:   PetscSectionGetMaxDof(section, &maxDof);
3514:   PetscSectionGetChart(section, &pStart, &pEnd);
3515:   PetscMalloc1(maxDof, &indices);
3516:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3517:   for (p = pStart; p < pEnd; ++p) {
3518:     PetscInt cdof, d;

3520:     PetscSectionGetConstraintDof(section, p, &cdof);
3521:     if (cdof) {
3522:       if (numFields) {
3523:         PetscInt numConst = 0, foff = 0;

3525:         for (f = 0; f < numFields; ++f) {
3526:           const PetscInt *find;
3527:           PetscInt        fcdof, fdof;

3529:           PetscSectionGetFieldDof(section, p, f, &fdof);
3530:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3531:           /* Change constraint numbering from field component to local dof number */
3532:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3533:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3534:           numConst += fcdof;
3535:           foff     += fdof;
3536:         }
3537:         if (cdof != numConst) {PetscSectionSetConstraintDof(section, p, numConst);}
3538:       } else {
3539:         for (d = 0; d < cdof; ++d) indices[d] = d;
3540:       }
3541:       PetscSectionSetConstraintIndices(section, p, indices);
3542:     }
3543:   }
3544:   PetscFree(indices);
3545:   return(0);
3546: }

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

3551:   Not Collective

3553:   Input Parameters:
3554: + dm        - The DMPlex object
3555: . dim       - The spatial dimension of the problem
3556: . numFields - The number of fields in the problem
3557: . numComp   - An array of size numFields that holds the number of components for each field
3558: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3559: . numBC     - The number of boundary conditions
3560: . bcField   - An array of size numBC giving the field number for each boundry condition
3561: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3562: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3563: - perm      - Optional permutation of the chart, or NULL

3565:   Output Parameter:
3566: . section - The PetscSection object

3568:   Notes:
3569:     numDof[f*(dim+1)+d] gives the number of dof for field f on points of dimension d. For instance, numDof[1] is the
3570:   number of dof for field 0 on each edge.

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

3574:   Level: developer

3576:   Fortran Notes:
3577:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3579: .keywords: mesh, elements
3580: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3581: @*/
3582: PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], IS perm, PetscSection *section)
3583: {
3584:   PetscSection   aSec;

3588:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3589:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3590:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3591:   PetscSectionSetUp(*section);
3592:   DMPlexGetAnchors(dm,&aSec,NULL);
3593:   if (numBC || aSec) {
3594:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3595:     DMPlexCreateSectionBCIndices(dm, *section);
3596:   }
3597:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3598:   return(0);
3599: }

3601: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3602: {
3603:   PetscSection   section, s;
3604:   Mat            m;
3605:   PetscInt       maxHeight;

3609:   DMClone(dm, cdm);
3610:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3611:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3612:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3613:   DMSetSection(*cdm, section);
3614:   PetscSectionDestroy(&section);
3615:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3616:   MatCreate(PETSC_COMM_SELF, &m);
3617:   DMSetDefaultConstraints(*cdm, s, m);
3618:   PetscSectionDestroy(&s);
3619:   MatDestroy(&m);
3620:   return(0);
3621: }

3623: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3624: {
3625:   Vec            coordsLocal;
3626:   DM             coordsDM;

3630:   *field = NULL;
3631:   DMGetCoordinatesLocal(dm,&coordsLocal);
3632:   DMGetCoordinateDM(dm,&coordsDM);
3633:   if (coordsLocal && coordsDM) {
3634:     DMFieldCreateDS(coordsDM, 0, coordsLocal, field);
3635:   }
3636:   return(0);
3637: }

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

3642:   Not Collective

3644:   Input Parameters:
3645: . dm        - The DMPlex object

3647:   Output Parameter:
3648: . section - The PetscSection object

3650:   Level: developer

3652: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3653: @*/
3654: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3655: {
3656:   DM_Plex *mesh = (DM_Plex*) dm->data;

3660:   if (section) *section = mesh->coneSection;
3661:   return(0);
3662: }

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

3667:   Not Collective

3669:   Input Parameters:
3670: . dm        - The DMPlex object

3672:   Output Parameter:
3673: . section - The PetscSection object

3675:   Level: developer

3677: .seealso: DMPlexGetConeSection()
3678: @*/
3679: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3680: {
3681:   DM_Plex *mesh = (DM_Plex*) dm->data;

3685:   if (section) *section = mesh->supportSection;
3686:   return(0);
3687: }

3689: /*@C
3690:   DMPlexGetCones - Return cone data

3692:   Not Collective

3694:   Input Parameters:
3695: . dm        - The DMPlex object

3697:   Output Parameter:
3698: . cones - The cone for each point

3700:   Level: developer

3702: .seealso: DMPlexGetConeSection()
3703: @*/
3704: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3705: {
3706:   DM_Plex *mesh = (DM_Plex*) dm->data;

3710:   if (cones) *cones = mesh->cones;
3711:   return(0);
3712: }

3714: /*@C
3715:   DMPlexGetConeOrientations - Return cone orientation data

3717:   Not Collective

3719:   Input Parameters:
3720: . dm        - The DMPlex object

3722:   Output Parameter:
3723: . coneOrientations - The cone orientation for each point

3725:   Level: developer

3727: .seealso: DMPlexGetConeSection()
3728: @*/
3729: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3730: {
3731:   DM_Plex *mesh = (DM_Plex*) dm->data;

3735:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3736:   return(0);
3737: }

3739: /******************************** FEM Support **********************************/

3741: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3742: {
3743:   DMLabel        label;
3744:   PetscInt      *perm;
3745:   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3749:   if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3750:   DMGetDimension(dm, &dim);
3751:   DMPlexGetDepthLabel(dm, &label);
3752:   DMLabelGetValue(label, point, &depth);
3753:   if (depth == 1) {eStart = point;}
3754:   else if  (depth == dim) {
3755:     const PetscInt *cone;

3757:     DMPlexGetCone(dm, point, &cone);
3758:     eStart = cone[0];
3759:   } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering", point, depth);
3760:   if (!section) {DMGetSection(dm, &section);}
3761:   PetscSectionGetNumFields(section, &Nf);
3762:   if (dim <= 1) return(0);
3763:   for (f = 0; f < Nf; ++f) {
3764:     /* An order k SEM disc has k-1 dofs on an edge */
3765:     PetscSectionGetFieldDof(section, eStart, f, &k);
3766:     PetscSectionGetFieldComponents(section, f, &Nc);
3767:     k = k/Nc + 1;
3768:     size += PetscPowInt(k+1, dim)*Nc;
3769:   }
3770:   PetscMalloc1(size, &perm);
3771:   for (f = 0; f < Nf; ++f) {
3772:     switch (dim) {
3773:     case 2:
3774:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3775:       PetscSectionGetFieldDof(section, eStart, f, &k);
3776:       PetscSectionGetFieldComponents(section, f, &Nc);
3777:       k = k/Nc + 1;
3778:       /* The SEM order is

3780:          v_lb, {e_b}, v_rb,
3781:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3782:          v_lt, reverse {e_t}, v_rt
3783:       */
3784:       {
3785:         const PetscInt of   = 0;
3786:         const PetscInt oeb  = of   + PetscSqr(k-1);
3787:         const PetscInt oer  = oeb  + (k-1);
3788:         const PetscInt oet  = oer  + (k-1);
3789:         const PetscInt oel  = oet  + (k-1);
3790:         const PetscInt ovlb = oel  + (k-1);
3791:         const PetscInt ovrb = ovlb + 1;
3792:         const PetscInt ovrt = ovrb + 1;
3793:         const PetscInt ovlt = ovrt + 1;
3794:         PetscInt       o;

3796:         /* bottom */
3797:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3798:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3799:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3800:         /* middle */
3801:         for (i = 0; i < k-1; ++i) {
3802:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3803:           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;
3804:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3805:         }
3806:         /* top */
3807:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3808:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3809:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3810:         foffset = offset;
3811:       }
3812:       break;
3813:     case 3:
3814:       /* The original hex closure is

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

3830:          Middle Slice (j)
3831:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3832:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3833:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

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

3870:         /* Bottom Slice */
3871:         /*   bottom */
3872:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3873:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3874:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3875:         /*   middle */
3876:         for (i = 0; i < k-1; ++i) {
3877:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3878:           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;}
3879:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3880:         }
3881:         /*   top */
3882:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3883:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3884:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3886:         /* Middle Slice */
3887:         for (j = 0; j < k-1; ++j) {
3888:           /*   bottom */
3889:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3890:           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;
3891:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3892:           /*   middle */
3893:           for (i = 0; i < k-1; ++i) {
3894:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3895:             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;
3896:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3897:           }
3898:           /*   top */
3899:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3900:           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;
3901:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3902:         }

3904:         /* Top Slice */
3905:         /*   bottom */
3906:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3907:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3908:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3909:         /*   middle */
3910:         for (i = 0; i < k-1; ++i) {
3911:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3912:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3913:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3914:         }
3915:         /*   top */
3916:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3917:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3918:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3920:         foffset = offset;
3921:       }
3922:       break;
3923:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3924:     }
3925:   }
3926:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3927:   /* Check permutation */
3928:   {
3929:     PetscInt *check;

3931:     PetscMalloc1(size, &check);
3932:     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]);}
3933:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3934:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3935:     PetscFree(check);
3936:   }
3937:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3938:   return(0);
3939: }

3941: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3942: {
3943:   PetscDS        prob;
3944:   PetscInt       depth, Nf, h;
3945:   DMLabel        label;

3949:   prob    = dm->prob;
3950:   Nf      = prob->Nf;
3951:   label   = dm->depthLabel;
3952:   *dspace = NULL;
3953:   if (field < Nf) {
3954:     PetscObject disc = prob->disc[field];

3956:     if (disc->classid == PETSCFE_CLASSID) {
3957:       PetscDualSpace dsp;

3959:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3960:       DMLabelGetNumValues(label,&depth);
3961:       DMLabelGetValue(label,point,&h);
3962:       h    = depth - 1 - h;
3963:       if (h) {
3964:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3965:       } else {
3966:         *dspace = dsp;
3967:       }
3968:     }
3969:   }
3970:   return(0);
3971: }


3974: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3975: {
3976:   PetscScalar    *array, *vArray;
3977:   const PetscInt *cone, *coneO;
3978:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3979:   PetscErrorCode  ierr;

3982:   PetscSectionGetChart(section, &pStart, &pEnd);
3983:   DMPlexGetConeSize(dm, point, &numPoints);
3984:   DMPlexGetCone(dm, point, &cone);
3985:   DMPlexGetConeOrientation(dm, point, &coneO);
3986:   if (!values || !*values) {
3987:     if ((point >= pStart) && (point < pEnd)) {
3988:       PetscInt dof;

3990:       PetscSectionGetDof(section, point, &dof);
3991:       size += dof;
3992:     }
3993:     for (p = 0; p < numPoints; ++p) {
3994:       const PetscInt cp = cone[p];
3995:       PetscInt       dof;

3997:       if ((cp < pStart) || (cp >= pEnd)) continue;
3998:       PetscSectionGetDof(section, cp, &dof);
3999:       size += dof;
4000:     }
4001:     if (!values) {
4002:       if (csize) *csize = size;
4003:       return(0);
4004:     }
4005:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
4006:   } else {
4007:     array = *values;
4008:   }
4009:   size = 0;
4010:   VecGetArray(v, &vArray);
4011:   if ((point >= pStart) && (point < pEnd)) {
4012:     PetscInt     dof, off, d;
4013:     PetscScalar *varr;

4015:     PetscSectionGetDof(section, point, &dof);
4016:     PetscSectionGetOffset(section, point, &off);
4017:     varr = &vArray[off];
4018:     for (d = 0; d < dof; ++d, ++offset) {
4019:       array[offset] = varr[d];
4020:     }
4021:     size += dof;
4022:   }
4023:   for (p = 0; p < numPoints; ++p) {
4024:     const PetscInt cp = cone[p];
4025:     PetscInt       o  = coneO[p];
4026:     PetscInt       dof, off, d;
4027:     PetscScalar   *varr;

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

4055: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4056: {
4057:   const PetscInt *cla;
4058:   PetscInt       np, *pts = NULL;

4062:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
4063:   if (!*clPoints) {
4064:     PetscInt pStart, pEnd, p, q;

4066:     PetscSectionGetChart(section, &pStart, &pEnd);
4067:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
4068:     /* Compress out points not in the section */
4069:     for (p = 0, q = 0; p < np; p++) {
4070:       PetscInt r = pts[2*p];
4071:       if ((r >= pStart) && (r < pEnd)) {
4072:         pts[q*2]   = r;
4073:         pts[q*2+1] = pts[2*p+1];
4074:         ++q;
4075:       }
4076:     }
4077:     np = q;
4078:     cla = NULL;
4079:   } else {
4080:     PetscInt dof, off;

4082:     PetscSectionGetDof(*clSec, point, &dof);
4083:     PetscSectionGetOffset(*clSec, point, &off);
4084:     ISGetIndices(*clPoints, &cla);
4085:     np   = dof/2;
4086:     pts  = (PetscInt *) &cla[off];
4087:   }
4088:   *numPoints = np;
4089:   *points    = pts;
4090:   *clp       = cla;

4092:   return(0);
4093: }

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

4100:   if (!*clPoints) {
4101:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
4102:   } else {
4103:     ISRestoreIndices(*clPoints, clp);
4104:   }
4105:   *numPoints = 0;
4106:   *points    = NULL;
4107:   *clSec     = NULL;
4108:   *clPoints  = NULL;
4109:   *clp       = NULL;
4110:   return(0);
4111: }

4113: 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[])
4114: {
4115:   PetscInt          offset = 0, p;
4116:   const PetscInt    **perms = NULL;
4117:   const PetscScalar **flips = NULL;
4118:   PetscErrorCode    ierr;

4121:   *size = 0;
4122:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4123:   for (p = 0; p < numPoints; p++) {
4124:     const PetscInt    point = points[2*p];
4125:     const PetscInt    *perm = perms ? perms[p] : NULL;
4126:     const PetscScalar *flip = flips ? flips[p] : NULL;
4127:     PetscInt          dof, off, d;
4128:     const PetscScalar *varr;

4130:     PetscSectionGetDof(section, point, &dof);
4131:     PetscSectionGetOffset(section, point, &off);
4132:     varr = &vArray[off];
4133:     if (clperm) {
4134:       if (perm) {
4135:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4136:       } else {
4137:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4138:       }
4139:       if (flip) {
4140:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4141:       }
4142:     } else {
4143:       if (perm) {
4144:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4145:       } else {
4146:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4147:       }
4148:       if (flip) {
4149:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4150:       }
4151:     }
4152:     offset += dof;
4153:   }
4154:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4155:   *size = offset;
4156:   return(0);
4157: }

4159: 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[])
4160: {
4161:   PetscInt          offset = 0, f;
4162:   PetscErrorCode    ierr;

4165:   *size = 0;
4166:   for (f = 0; f < numFields; ++f) {
4167:     PetscInt          p;
4168:     const PetscInt    **perms = NULL;
4169:     const PetscScalar **flips = NULL;

4171:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4172:     for (p = 0; p < numPoints; p++) {
4173:       const PetscInt    point = points[2*p];
4174:       PetscInt          fdof, foff, b;
4175:       const PetscScalar *varr;
4176:       const PetscInt    *perm = perms ? perms[p] : NULL;
4177:       const PetscScalar *flip = flips ? flips[p] : NULL;

4179:       PetscSectionGetFieldDof(section, point, f, &fdof);
4180:       PetscSectionGetFieldOffset(section, point, f, &foff);
4181:       varr = &vArray[foff];
4182:       if (clperm) {
4183:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4184:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4185:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4186:       } else {
4187:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4188:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4189:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4190:       }
4191:       offset += fdof;
4192:     }
4193:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4194:   }
4195:   *size = offset;
4196:   return(0);
4197: }

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

4202:   Not collective

4204:   Input Parameters:
4205: + dm - The DM
4206: . section - The section describing the layout in v, or NULL to use the default section
4207: . v - The local vector
4208: . point - The point in the DM
4209: . csize - The size of the input values array, or NULL
4210: - values - An array to use for the values, or NULL to have it allocated automatically

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

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

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

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

4247:   Level: intermediate

4249: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4250: @*/
4251: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4252: {
4253:   PetscSection       clSection;
4254:   IS                 clPoints;
4255:   PetscScalar       *array;
4256:   const PetscScalar *vArray;
4257:   PetscInt          *points = NULL;
4258:   const PetscInt    *clp, *perm;
4259:   PetscInt           depth, numFields, numPoints, size;
4260:   PetscErrorCode     ierr;

4264:   if (!section) {DMGetSection(dm, &section);}
4267:   DMPlexGetDepth(dm, &depth);
4268:   PetscSectionGetNumFields(section, &numFields);
4269:   if (depth == 1 && numFields < 2) {
4270:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4271:     return(0);
4272:   }
4273:   /* Get points */
4274:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4275:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4276:   /* Get array */
4277:   if (!values || !*values) {
4278:     PetscInt asize = 0, dof, p;

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

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

4314:   Not collective

4316:   Input Parameters:
4317: + dm - The DM
4318: . section - The section describing the layout in v, or NULL to use the default section
4319: . v - The local vector
4320: . point - The point in the DM
4321: . csize - The number of values in the closure, or NULL
4322: - values - The array of values, which is a borrowed array and should not be freed

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

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

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

4332:   Level: intermediate

4334: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4335: @*/
4336: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4337: {
4338:   PetscInt       size = 0;

4342:   /* Should work without recalculating size */
4343:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4344:   *values = NULL;
4345:   return(0);
4346: }

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

4351: 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[])
4352: {
4353:   PetscInt        cdof;   /* The number of constraints on this point */
4354:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4355:   PetscScalar    *a;
4356:   PetscInt        off, cind = 0, k;
4357:   PetscErrorCode  ierr;

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

4401: 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[])
4402: {
4403:   PetscInt        cdof;   /* The number of constraints on this point */
4404:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4405:   PetscScalar    *a;
4406:   PetscInt        off, cind = 0, k;
4407:   PetscErrorCode  ierr;

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

4452: 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[])
4453: {
4454:   PetscScalar    *a;
4455:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4456:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4457:   PetscInt        cind = 0, b;
4458:   PetscErrorCode  ierr;

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

4505: 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[])
4506: {
4507:   PetscScalar    *a;
4508:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4509:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4510:   PetscInt        cind = 0, ncind = 0, b;
4511:   PetscBool       ncSet, fcSet;
4512:   PetscErrorCode  ierr;

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

4596: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4597: {
4598:   PetscScalar    *array;
4599:   const PetscInt *cone, *coneO;
4600:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4601:   PetscErrorCode  ierr;

4604:   PetscSectionGetChart(section, &pStart, &pEnd);
4605:   DMPlexGetConeSize(dm, point, &numPoints);
4606:   DMPlexGetCone(dm, point, &cone);
4607:   DMPlexGetConeOrientation(dm, point, &coneO);
4608:   VecGetArray(v, &array);
4609:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4610:     const PetscInt cp = !p ? point : cone[p-1];
4611:     const PetscInt o  = !p ? 0     : coneO[p-1];

4613:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4614:     PetscSectionGetDof(section, cp, &dof);
4615:     /* ADD_VALUES */
4616:     {
4617:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4618:       PetscScalar    *a;
4619:       PetscInt        cdof, coff, cind = 0, k;

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

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

4657:   Not collective

4659:   Input Parameters:
4660: + dm - The DM
4661: . section - The section describing the layout in v, or NULL to use the default section
4662: . v - The local vector
4663: . point - The point in the DM
4664: . values - The array of values
4665: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4666:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

4671:   Level: intermediate

4673: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4674: @*/
4675: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4676: {
4677:   PetscSection    clSection;
4678:   IS              clPoints;
4679:   PetscScalar    *array;
4680:   PetscInt       *points = NULL;
4681:   const PetscInt *clp, *clperm;
4682:   PetscInt        depth, numFields, numPoints, p;
4683:   PetscErrorCode  ierr;

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

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

4762:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4763:     switch (mode) {
4764:     case INSERT_VALUES:
4765:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4766:         const PetscInt    point = points[2*p];
4767:         const PetscInt    *perm = perms ? perms[p] : NULL;
4768:         const PetscScalar *flip = flips ? flips[p] : NULL;
4769:         PetscSectionGetDof(section, point, &dof);
4770:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4771:       } break;
4772:     case INSERT_ALL_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_TRUE,  perm, flip, clperm, values, off, array);
4779:       } break;
4780:     case INSERT_BC_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:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4787:       } break;
4788:     case ADD_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:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4795:       } break;
4796:     case ADD_ALL_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_TRUE,  perm, flip, clperm, values, off, array);
4803:       } break;
4804:     case ADD_BC_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:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4811:       } break;
4812:     default:
4813:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4814:     }
4815:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4816:   }
4817:   /* Cleanup points */
4818:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4819:   /* Cleanup array */
4820:   VecRestoreArray(v, &array);
4821:   return(0);
4822: }

4824: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4825: {
4826:   PetscSection      clSection;
4827:   IS                clPoints;
4828:   PetscScalar       *array;
4829:   PetscInt          *points = NULL;
4830:   const PetscInt    *clp, *clperm;
4831:   PetscInt          numFields, numPoints, p;
4832:   PetscInt          offset = 0, f;
4833:   PetscErrorCode    ierr;

4837:   if (!section) {DMGetSection(dm, &section);}
4840:   PetscSectionGetNumFields(section, &numFields);
4841:   /* Get points */
4842:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4843:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4844:   /* Get array */
4845:   VecGetArray(v, &array);
4846:   /* Get values */
4847:   for (f = 0; f < numFields; ++f) {
4848:     const PetscInt    **perms = NULL;
4849:     const PetscScalar **flips = NULL;

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

4908: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4909: {
4910:   PetscMPIInt    rank;
4911:   PetscInt       i, j;

4915:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4916:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4917:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4918:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4919:   numCIndices = numCIndices ? numCIndices : numRIndices;
4920:   for (i = 0; i < numRIndices; i++) {
4921:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4922:     for (j = 0; j < numCIndices; j++) {
4923: #if defined(PETSC_USE_COMPLEX)
4924:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4925: #else
4926:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4927: #endif
4928:     }
4929:     PetscViewerASCIIPrintf(viewer, "\n");
4930:   }
4931:   return(0);
4932: }

4934: /* . off - The global offset of this point */
4935: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4936: {
4937:   PetscInt        dof;    /* The number of unknowns on this point */
4938:   PetscInt        cdof;   /* The number of constraints on this point */
4939:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4940:   PetscInt        cind = 0, k;
4941:   PetscErrorCode  ierr;

4944:   PetscSectionGetDof(section, point, &dof);
4945:   PetscSectionGetConstraintDof(section, point, &cdof);
4946:   if (!cdof || setBC) {
4947:     if (perm) {
4948:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4949:     } else {
4950:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4951:     }
4952:   } else {
4953:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4954:     if (perm) {
4955:       for (k = 0; k < dof; ++k) {
4956:         if ((cind < cdof) && (k == cdofs[cind])) {
4957:           /* Insert check for returning constrained indices */
4958:           indices[*loff+perm[k]] = -(off+k+1);
4959:           ++cind;
4960:         } else {
4961:           indices[*loff+perm[k]] = off+k-cind;
4962:         }
4963:       }
4964:     } else {
4965:       for (k = 0; k < dof; ++k) {
4966:         if ((cind < cdof) && (k == cdofs[cind])) {
4967:           /* Insert check for returning constrained indices */
4968:           indices[*loff+k] = -(off+k+1);
4969:           ++cind;
4970:         } else {
4971:           indices[*loff+k] = off+k-cind;
4972:         }
4973:       }
4974:     }
4975:   }
4976:   *loff += dof;
4977:   return(0);
4978: }

4980: /*
4981:   This version only believes the point offset from the globalSection

4983:  . off - The global offset of this point
4984: */
4985: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
4986: {
4987:   PetscInt       numFields, foff, f;

4991:   PetscSectionGetNumFields(section, &numFields);
4992:   for (f = 0, foff = 0; f < numFields; ++f) {
4993:     PetscInt        fdof, cfdof;
4994:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4995:     PetscInt        cind = 0, b;
4996:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4998:     PetscSectionGetFieldDof(section, point, f, &fdof);
4999:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5000:     if (!cfdof || setBC) {
5001:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
5002:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
5003:     } else {
5004:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5005:       if (perm) {
5006:         for (b = 0; b < fdof; b++) {
5007:           if ((cind < cfdof) && (b == fcdofs[cind])) {
5008:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
5009:             ++cind;
5010:           } else {
5011:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
5012:           }
5013:         }
5014:       } else {
5015:         for (b = 0; b < fdof; b++) {
5016:           if ((cind < cfdof) && (b == fcdofs[cind])) {
5017:             indices[foffs[f]+b] = -(off+foff+b+1);
5018:             ++cind;
5019:           } else {
5020:             indices[foffs[f]+b] = off+foff+b-cind;
5021:           }
5022:         }
5023:       }
5024:     }
5025:     foff     += (setBC ? fdof : (fdof - cfdof));
5026:     foffs[f] += fdof;
5027:   }
5028:   return(0);
5029: }

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

5034:  . foffs - The offset into 'indices' for each field, since it is segregated by field
5035: */
5036: PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, PetscInt indices[])
5037: {
5038:   PetscInt       numFields, foff, f;

5042:   PetscSectionGetNumFields(section, &numFields);
5043:   for (f = 0; f < numFields; ++f) {
5044:     PetscInt        fdof, cfdof;
5045:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5046:     PetscInt        cind = 0, b;
5047:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

5049:     PetscSectionGetFieldDof(section, point, f, &fdof);
5050:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5051:     PetscSectionGetFieldOffset(globalSection, point, f, &foff);
5052:     if (!cfdof || setBC) {
5053:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = foff+b;}}
5054:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = foff+b;}}
5055:     } else {
5056:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5057:       if (perm) {
5058:         for (b = 0; b < fdof; b++) {
5059:           if ((cind < cfdof) && (b == fcdofs[cind])) {
5060:             indices[foffs[f]+perm[b]] = -(foff+b+1);
5061:             ++cind;
5062:           } else {
5063:             indices[foffs[f]+perm[b]] = foff+b-cind;
5064:           }
5065:         }
5066:       } else {
5067:         for (b = 0; b < fdof; b++) {
5068:           if ((cind < cfdof) && (b == fcdofs[cind])) {
5069:             indices[foffs[f]+b] = -(foff+b+1);
5070:             ++cind;
5071:           } else {
5072:             indices[foffs[f]+b] = foff+b-cind;
5073:           }
5074:         }
5075:       }
5076:     }
5077:     foffs[f] += fdof;
5078:   }
5079:   return(0);
5080: }

5082: 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)
5083: {
5084:   Mat             cMat;
5085:   PetscSection    aSec, cSec;
5086:   IS              aIS;
5087:   PetscInt        aStart = -1, aEnd = -1;
5088:   const PetscInt  *anchors;
5089:   PetscInt        numFields, f, p, q, newP = 0;
5090:   PetscInt        newNumPoints = 0, newNumIndices = 0;
5091:   PetscInt        *newPoints, *indices, *newIndices;
5092:   PetscInt        maxAnchor, maxDof;
5093:   PetscInt        newOffsets[32];
5094:   PetscInt        *pointMatOffsets[32];
5095:   PetscInt        *newPointOffsets[32];
5096:   PetscScalar     *pointMat[32];
5097:   PetscScalar     *newValues=NULL,*tmpValues;
5098:   PetscBool       anyConstrained = PETSC_FALSE;
5099:   PetscErrorCode  ierr;

5104:   PetscSectionGetNumFields(section, &numFields);

5106:   DMPlexGetAnchors(dm,&aSec,&aIS);
5107:   /* if there are point-to-point constraints */
5108:   if (aSec) {
5109:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
5110:     ISGetIndices(aIS,&anchors);
5111:     PetscSectionGetChart(aSec,&aStart,&aEnd);
5112:     /* figure out how many points are going to be in the new element matrix
5113:      * (we allow double counting, because it's all just going to be summed
5114:      * into the global matrix anyway) */
5115:     for (p = 0; p < 2*numPoints; p+=2) {
5116:       PetscInt b    = points[p];
5117:       PetscInt bDof = 0, bSecDof;

5119:       PetscSectionGetDof(section,b,&bSecDof);
5120:       if (!bSecDof) {
5121:         continue;
5122:       }
5123:       if (b >= aStart && b < aEnd) {
5124:         PetscSectionGetDof(aSec,b,&bDof);
5125:       }
5126:       if (bDof) {
5127:         /* this point is constrained */
5128:         /* it is going to be replaced by its anchors */
5129:         PetscInt bOff, q;

5131:         anyConstrained = PETSC_TRUE;
5132:         newNumPoints  += bDof;
5133:         PetscSectionGetOffset(aSec,b,&bOff);
5134:         for (q = 0; q < bDof; q++) {
5135:           PetscInt a = anchors[bOff + q];
5136:           PetscInt aDof;

5138:           PetscSectionGetDof(section,a,&aDof);
5139:           newNumIndices += aDof;
5140:           for (f = 0; f < numFields; ++f) {
5141:             PetscInt fDof;

5143:             PetscSectionGetFieldDof(section, a, f, &fDof);
5144:             newOffsets[f+1] += fDof;
5145:           }
5146:         }
5147:       }
5148:       else {
5149:         /* this point is not constrained */
5150:         newNumPoints++;
5151:         newNumIndices += bSecDof;
5152:         for (f = 0; f < numFields; ++f) {
5153:           PetscInt fDof;

5155:           PetscSectionGetFieldDof(section, b, f, &fDof);
5156:           newOffsets[f+1] += fDof;
5157:         }
5158:       }
5159:     }
5160:   }
5161:   if (!anyConstrained) {
5162:     if (outNumPoints)  *outNumPoints  = 0;
5163:     if (outNumIndices) *outNumIndices = 0;
5164:     if (outPoints)     *outPoints     = NULL;
5165:     if (outValues)     *outValues     = NULL;
5166:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5167:     return(0);
5168:   }

5170:   if (outNumPoints)  *outNumPoints  = newNumPoints;
5171:   if (outNumIndices) *outNumIndices = newNumIndices;

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

5175:   if (!outPoints && !outValues) {
5176:     if (offsets) {
5177:       for (f = 0; f <= numFields; f++) {
5178:         offsets[f] = newOffsets[f];
5179:       }
5180:     }
5181:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
5182:     return(0);
5183:   }

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

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

5189:   /* workspaces */
5190:   if (numFields) {
5191:     for (f = 0; f < numFields; f++) {
5192:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5193:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5194:     }
5195:   }
5196:   else {
5197:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5198:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5199:   }

5201:   /* get workspaces for the point-to-point matrices */
5202:   if (numFields) {
5203:     PetscInt totalOffset, totalMatOffset;

5205:     for (p = 0; p < numPoints; p++) {
5206:       PetscInt b    = points[2*p];
5207:       PetscInt bDof = 0, bSecDof;

5209:       PetscSectionGetDof(section,b,&bSecDof);
5210:       if (!bSecDof) {
5211:         for (f = 0; f < numFields; f++) {
5212:           newPointOffsets[f][p + 1] = 0;
5213:           pointMatOffsets[f][p + 1] = 0;
5214:         }
5215:         continue;
5216:       }
5217:       if (b >= aStart && b < aEnd) {
5218:         PetscSectionGetDof(aSec, b, &bDof);
5219:       }
5220:       if (bDof) {
5221:         for (f = 0; f < numFields; f++) {
5222:           PetscInt fDof, q, bOff, allFDof = 0;

5224:           PetscSectionGetFieldDof(section, b, f, &fDof);
5225:           PetscSectionGetOffset(aSec, b, &bOff);
5226:           for (q = 0; q < bDof; q++) {
5227:             PetscInt a = anchors[bOff + q];
5228:             PetscInt aFDof;

5230:             PetscSectionGetFieldDof(section, a, f, &aFDof);
5231:             allFDof += aFDof;
5232:           }
5233:           newPointOffsets[f][p+1] = allFDof;
5234:           pointMatOffsets[f][p+1] = fDof * allFDof;
5235:         }
5236:       }
5237:       else {
5238:         for (f = 0; f < numFields; f++) {
5239:           PetscInt fDof;

5241:           PetscSectionGetFieldDof(section, b, f, &fDof);
5242:           newPointOffsets[f][p+1] = fDof;
5243:           pointMatOffsets[f][p+1] = 0;
5244:         }
5245:       }
5246:     }
5247:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5248:       newPointOffsets[f][0] = totalOffset;
5249:       pointMatOffsets[f][0] = totalMatOffset;
5250:       for (p = 0; p < numPoints; p++) {
5251:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5252:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5253:       }
5254:       totalOffset    = newPointOffsets[f][numPoints];
5255:       totalMatOffset = pointMatOffsets[f][numPoints];
5256:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5257:     }
5258:   }
5259:   else {
5260:     for (p = 0; p < numPoints; p++) {
5261:       PetscInt b    = points[2*p];
5262:       PetscInt bDof = 0, bSecDof;

5264:       PetscSectionGetDof(section,b,&bSecDof);
5265:       if (!bSecDof) {
5266:         newPointOffsets[0][p + 1] = 0;
5267:         pointMatOffsets[0][p + 1] = 0;
5268:         continue;
5269:       }
5270:       if (b >= aStart && b < aEnd) {
5271:         PetscSectionGetDof(aSec, b, &bDof);
5272:       }
5273:       if (bDof) {
5274:         PetscInt bOff, q, allDof = 0;

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

5280:           PetscSectionGetDof(section, a, &aDof);
5281:           allDof += aDof;
5282:         }
5283:         newPointOffsets[0][p+1] = allDof;
5284:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5285:       }
5286:       else {
5287:         newPointOffsets[0][p+1] = bSecDof;
5288:         pointMatOffsets[0][p+1] = 0;
5289:       }
5290:     }
5291:     newPointOffsets[0][0] = 0;
5292:     pointMatOffsets[0][0] = 0;
5293:     for (p = 0; p < numPoints; p++) {
5294:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5295:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5296:     }
5297:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5298:   }

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

5303:   /* get the point-to-point matrices; construct newPoints */
5304:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5305:   PetscSectionGetMaxDof(section, &maxDof);
5306:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5307:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5308:   if (numFields) {
5309:     for (p = 0, newP = 0; p < numPoints; p++) {
5310:       PetscInt b    = points[2*p];
5311:       PetscInt o    = points[2*p+1];
5312:       PetscInt bDof = 0, bSecDof;

5314:       PetscSectionGetDof(section, b, &bSecDof);
5315:       if (!bSecDof) {
5316:         continue;
5317:       }
5318:       if (b >= aStart && b < aEnd) {
5319:         PetscSectionGetDof(aSec, b, &bDof);
5320:       }
5321:       if (bDof) {
5322:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5324:         fStart[0] = 0;
5325:         fEnd[0]   = 0;
5326:         for (f = 0; f < numFields; f++) {
5327:           PetscInt fDof;

5329:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5330:           fStart[f+1] = fStart[f] + fDof;
5331:           fEnd[f+1]   = fStart[f+1];
5332:         }
5333:         PetscSectionGetOffset(cSec, b, &bOff);
5334:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

5336:         fAnchorStart[0] = 0;
5337:         fAnchorEnd[0]   = 0;
5338:         for (f = 0; f < numFields; f++) {
5339:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5341:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5342:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5343:         }
5344:         PetscSectionGetOffset(aSec, b, &bOff);
5345:         for (q = 0; q < bDof; q++) {
5346:           PetscInt a = anchors[bOff + q], aOff;

5348:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5349:           newPoints[2*(newP + q)]     = a;
5350:           newPoints[2*(newP + q) + 1] = 0;
5351:           PetscSectionGetOffset(section, a, &aOff);
5352:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5353:         }
5354:         newP += bDof;

5356:         if (outValues) {
5357:           /* get the point-to-point submatrix */
5358:           for (f = 0; f < numFields; f++) {
5359:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5360:           }
5361:         }
5362:       }
5363:       else {
5364:         newPoints[2 * newP]     = b;
5365:         newPoints[2 * newP + 1] = o;
5366:         newP++;
5367:       }
5368:     }
5369:   } else {
5370:     for (p = 0; p < numPoints; p++) {
5371:       PetscInt b    = points[2*p];
5372:       PetscInt o    = points[2*p+1];
5373:       PetscInt bDof = 0, bSecDof;

5375:       PetscSectionGetDof(section, b, &bSecDof);
5376:       if (!bSecDof) {
5377:         continue;
5378:       }
5379:       if (b >= aStart && b < aEnd) {
5380:         PetscSectionGetDof(aSec, b, &bDof);
5381:       }
5382:       if (bDof) {
5383:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5394:           newPoints[2*(newP + q)]     = a;
5395:           newPoints[2*(newP + q) + 1] = 0;
5396:           PetscSectionGetOffset(section, a, &aOff);
5397:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5398:         }
5399:         newP += bDof;

5401:         /* get the point-to-point submatrix */
5402:         if (outValues) {
5403:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5404:         }
5405:       }
5406:       else {
5407:         newPoints[2 * newP]     = b;
5408:         newPoints[2 * newP + 1] = o;
5409:         newP++;
5410:       }
5411:     }
5412:   }

5414:   if (outValues) {
5415:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5416:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5417:     /* multiply constraints on the right */
5418:     if (numFields) {
5419:       for (f = 0; f < numFields; f++) {
5420:         PetscInt oldOff = offsets[f];

5422:         for (p = 0; p < numPoints; p++) {
5423:           PetscInt cStart = newPointOffsets[f][p];
5424:           PetscInt b      = points[2 * p];
5425:           PetscInt c, r, k;
5426:           PetscInt dof;

5428:           PetscSectionGetFieldDof(section,b,f,&dof);
5429:           if (!dof) {
5430:             continue;
5431:           }
5432:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5433:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5434:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5436:             for (r = 0; r < numIndices; r++) {
5437:               for (c = 0; c < nCols; c++) {
5438:                 for (k = 0; k < dof; k++) {
5439:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5440:                 }
5441:               }
5442:             }
5443:           }
5444:           else {
5445:             /* copy this column as is */
5446:             for (r = 0; r < numIndices; r++) {
5447:               for (c = 0; c < dof; c++) {
5448:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5449:               }
5450:             }
5451:           }
5452:           oldOff += dof;
5453:         }
5454:       }
5455:     }
5456:     else {
5457:       PetscInt oldOff = 0;
5458:       for (p = 0; p < numPoints; p++) {
5459:         PetscInt cStart = newPointOffsets[0][p];
5460:         PetscInt b      = points[2 * p];
5461:         PetscInt c, r, k;
5462:         PetscInt dof;

5464:         PetscSectionGetDof(section,b,&dof);
5465:         if (!dof) {
5466:           continue;
5467:         }
5468:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5469:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5470:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5472:           for (r = 0; r < numIndices; r++) {
5473:             for (c = 0; c < nCols; c++) {
5474:               for (k = 0; k < dof; k++) {
5475:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5476:               }
5477:             }
5478:           }
5479:         }
5480:         else {
5481:           /* copy this column as is */
5482:           for (r = 0; r < numIndices; r++) {
5483:             for (c = 0; c < dof; c++) {
5484:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5485:             }
5486:           }
5487:         }
5488:         oldOff += dof;
5489:       }
5490:     }

5492:     if (multiplyLeft) {
5493:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5494:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5495:       /* multiply constraints transpose on the left */
5496:       if (numFields) {
5497:         for (f = 0; f < numFields; f++) {
5498:           PetscInt oldOff = offsets[f];

5500:           for (p = 0; p < numPoints; p++) {
5501:             PetscInt rStart = newPointOffsets[f][p];
5502:             PetscInt b      = points[2 * p];
5503:             PetscInt c, r, k;
5504:             PetscInt dof;

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

5511:               for (r = 0; r < nRows; r++) {
5512:                 for (c = 0; c < newNumIndices; c++) {
5513:                   for (k = 0; k < dof; k++) {
5514:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5515:                   }
5516:                 }
5517:               }
5518:             }
5519:             else {
5520:               /* copy this row as is */
5521:               for (r = 0; r < dof; r++) {
5522:                 for (c = 0; c < newNumIndices; c++) {
5523:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5524:                 }
5525:               }
5526:             }
5527:             oldOff += dof;
5528:           }
5529:         }
5530:       }
5531:       else {
5532:         PetscInt oldOff = 0;

5534:         for (p = 0; p < numPoints; p++) {
5535:           PetscInt rStart = newPointOffsets[0][p];
5536:           PetscInt b      = points[2 * p];
5537:           PetscInt c, r, k;
5538:           PetscInt dof;

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

5545:             for (r = 0; r < nRows; r++) {
5546:               for (c = 0; c < newNumIndices; c++) {
5547:                 for (k = 0; k < dof; k++) {
5548:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5549:                 }
5550:               }
5551:             }
5552:           }
5553:           else {
5554:             /* copy this row as is */
5555:             for (r = 0; r < dof; r++) {
5556:               for (c = 0; c < newNumIndices; c++) {
5557:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5558:               }
5559:             }
5560:           }
5561:           oldOff += dof;
5562:         }
5563:       }

5565:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5566:     }
5567:     else {
5568:       newValues = tmpValues;
5569:     }
5570:   }

5572:   /* clean up */
5573:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5574:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5576:   if (numFields) {
5577:     for (f = 0; f < numFields; f++) {
5578:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5579:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5580:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5581:     }
5582:   }
5583:   else {
5584:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5585:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5586:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5587:   }
5588:   ISRestoreIndices(aIS,&anchors);

5590:   /* output */
5591:   if (outPoints) {
5592:     *outPoints = newPoints;
5593:   }
5594:   else {
5595:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5596:   }
5597:   if (outValues) {
5598:     *outValues = newValues;
5599:   }
5600:   for (f = 0; f <= numFields; f++) {
5601:     offsets[f] = newOffsets[f];
5602:   }
5603:   return(0);
5604: }

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

5609:   Not collective

5611:   Input Parameters:
5612: + dm - The DM
5613: . section - The section describing the layout in v, or NULL to use the default section
5614: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5615: - point - The mesh point

5617:   Output parameters:
5618: + numIndices - The number of indices
5619: . indices - The indices
5620: - outOffsets - Field offset if not NULL

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

5624:   Level: advanced

5626: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5627: @*/
5628: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5629: {
5630:   PetscSection    clSection;
5631:   IS              clPoints;
5632:   const PetscInt *clp;
5633:   const PetscInt  **perms[32] = {NULL};
5634:   PetscInt       *points = NULL, *pointsNew;
5635:   PetscInt        numPoints, numPointsNew;
5636:   PetscInt        offsets[32];
5637:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5638:   PetscErrorCode  ierr;

5646:   PetscSectionGetNumFields(section, &Nf);
5647:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5648:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5649:   /* Get points in closure */
5650:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5651:   /* Get number of indices and indices per field */
5652:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5653:     PetscInt dof, fdof;

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

5694:       for (f = 0; f <= Nf; f++) {
5695:         outOffsets[f] = offsets[f];
5696:       }
5697:     }
5698:     for (p = 0; p < numPoints; p++) {
5699:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5700:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5701:     }
5702:   } else {
5703:     for (p = 0, off = 0; p < numPoints; p++) {
5704:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5706:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5707:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5708:     }
5709:   }
5710:   /* Cleanup points */
5711:   for (f = 0; f < PetscMax(1,Nf); f++) {
5712:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5713:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5714:   }
5715:   if (numPointsNew) {
5716:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5717:   } else {
5718:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5719:   }
5720:   if (numIndices) *numIndices = Nind;
5721:   return(0);
5722: }

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

5727:   Not collective

5729:   Input Parameters:
5730: + dm - The DM
5731: . section - The section describing the layout in v, or NULL to use the default section
5732: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5733: . point - The mesh point
5734: . numIndices - The number of indices
5735: . indices - The indices
5736: - outOffsets - Field offset if not NULL

5738:   Level: advanced

5740: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5741: @*/
5742: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5743: {

5749:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5750:   return(0);
5751: }

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

5756:   Not collective

5758:   Input Parameters:
5759: + dm - The DM
5760: . section - The section describing the layout in v, or NULL to use the default section
5761: . globalSection - The section describing the layout in v, or NULL to use the default global section
5762: . A - The matrix
5763: . point - The point in the DM
5764: . values - The array of values
5765: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5770:   Level: intermediate

5772: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5773: @*/
5774: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5775: {
5776:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5777:   PetscSection        clSection;
5778:   IS                  clPoints;
5779:   PetscInt           *points = NULL, *newPoints;
5780:   const PetscInt     *clp;
5781:   PetscInt           *indices;
5782:   PetscInt            offsets[32];
5783:   const PetscInt    **perms[32] = {NULL};
5784:   const PetscScalar **flips[32] = {NULL};
5785:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5786:   PetscScalar        *valCopy = NULL;
5787:   PetscScalar        *newValues;
5788:   PetscErrorCode      ierr;

5792:   if (!section) {DMGetSection(dm, &section);}
5794:   if (!globalSection) {DMGetGlobalSection(dm, &globalSection);}
5797:   PetscSectionGetNumFields(section, &numFields);
5798:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5799:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5800:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5801:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5802:     PetscInt fdof;

5804:     PetscSectionGetDof(section, points[p], &dof);
5805:     for (f = 0; f < numFields; ++f) {
5806:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5807:       offsets[f+1] += fdof;
5808:     }
5809:     numIndices += dof;
5810:   }
5811:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5825:         if (!numFields) {
5826:           PetscSectionGetDof(section,point,&fdof);
5827:         } else {
5828:           PetscSectionGetFieldDof(section,point,f,&fdof);
5829:         }
5830:         if (flip) {
5831:           PetscInt i, j, k;

5833:           if (!valCopy) {
5834:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5835:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5836:             values = valCopy;
5837:           }
5838:           for (i = 0; i < fdof; i++) {
5839:             PetscScalar fval = flip[i];

5841:             for (k = 0; k < numIndices; k++) {
5842:               valCopy[numIndices * (foffset + i) + k] *= fval;
5843:               valCopy[numIndices * k + (foffset + i)] *= fval;
5844:             }
5845:           }
5846:         }
5847:         foffset += fdof;
5848:       }
5849:     }
5850:   }
5851:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5852:   if (newNumPoints) {
5853:     if (valCopy) {
5854:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5855:     }
5856:     for (f = 0; f < PetscMax(1,numFields); f++) {
5857:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5858:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5859:     }
5860:     for (f = 0; f < PetscMax(1,numFields); f++) {
5861:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5862:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5863:     }
5864:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5865:     numPoints  = newNumPoints;
5866:     numIndices = newNumIndices;
5867:     points     = newPoints;
5868:     values     = newValues;
5869:   }
5870:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5871:   if (numFields) {
5872:     PetscBool useFieldOffsets;

5874:     PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);
5875:     if (useFieldOffsets) {
5876:       for (p = 0; p < numPoints; p++) {
5877:         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, indices);
5878:       }
5879:     } else {
5880:       for (p = 0; p < numPoints; p++) {
5881:         PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5882:         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5883:       }
5884:     }
5885:   } else {
5886:     for (p = 0, off = 0; p < numPoints; p++) {
5887:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5888:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5889:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5890:     }
5891:   }
5892:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5893:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5894:   if (mesh->printFEM > 1) {
5895:     PetscInt i;
5896:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5897:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5898:     PetscPrintf(PETSC_COMM_SELF, "\n");
5899:   }
5900:   if (ierr) {
5901:     PetscMPIInt    rank;
5902:     PetscErrorCode ierr2;

5904:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5905:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5906:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5907:     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5908: 
5909:   }
5910:   for (f = 0; f < PetscMax(1,numFields); f++) {
5911:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5912:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5913:   }
5914:   if (newNumPoints) {
5915:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5916:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5917:   }
5918:   else {
5919:     if (valCopy) {
5920:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5921:     }
5922:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5923:   }
5924:   DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
5925:   return(0);
5926: }

5928: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5929: {
5930:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5931:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5932:   PetscInt       *cpoints = NULL;
5933:   PetscInt       *findices, *cindices;
5934:   PetscInt        foffsets[32], coffsets[32];
5935:   CellRefiner     cellRefiner;
5936:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5937:   PetscErrorCode  ierr;

5942:   if (!fsection) {DMGetSection(dmf, &fsection);}
5944:   if (!csection) {DMGetSection(dmc, &csection);}
5946:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
5948:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
5951:   PetscSectionGetNumFields(fsection, &numFields);
5952:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5953:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5954:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5955:   /* Column indices */
5956:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5957:   maxFPoints = numCPoints;
5958:   /* Compress out points not in the section */
5959:   /*   TODO: Squeeze out points with 0 dof as well */
5960:   PetscSectionGetChart(csection, &pStart, &pEnd);
5961:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5962:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5963:       cpoints[q*2]   = cpoints[p];
5964:       cpoints[q*2+1] = cpoints[p+1];
5965:       ++q;
5966:     }
5967:   }
5968:   numCPoints = q;
5969:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5970:     PetscInt fdof;

5972:     PetscSectionGetDof(csection, cpoints[p], &dof);
5973:     if (!dof) continue;
5974:     for (f = 0; f < numFields; ++f) {
5975:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5976:       coffsets[f+1] += fdof;
5977:     }
5978:     numCIndices += dof;
5979:   }
5980:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5981:   /* Row indices */
5982:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5983:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5984:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5985:   for (r = 0, q = 0; r < numSubcells; ++r) {
5986:     /* TODO Map from coarse to fine cells */
5987:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5988:     /* Compress out points not in the section */
5989:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5990:     for (p = 0; p < numFPoints*2; p += 2) {
5991:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5992:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5993:         if (!dof) continue;
5994:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5995:         if (s < q) continue;
5996:         ftotpoints[q*2]   = fpoints[p];
5997:         ftotpoints[q*2+1] = fpoints[p+1];
5998:         ++q;
5999:       }
6000:     }
6001:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6002:   }
6003:   numFPoints = q;
6004:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6005:     PetscInt fdof;

6007:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6008:     if (!dof) continue;
6009:     for (f = 0; f < numFields; ++f) {
6010:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6011:       foffsets[f+1] += fdof;
6012:     }
6013:     numFIndices += dof;
6014:   }
6015:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

6017:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6018:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6019:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6020:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6021:   if (numFields) {
6022:     const PetscInt **permsF[32] = {NULL};
6023:     const PetscInt **permsC[32] = {NULL};

6025:     for (f = 0; f < numFields; f++) {
6026:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6027:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6028:     }
6029:     for (p = 0; p < numFPoints; p++) {
6030:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6031:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
6032:     }
6033:     for (p = 0; p < numCPoints; p++) {
6034:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6035:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6036:     }
6037:     for (f = 0; f < numFields; f++) {
6038:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6039:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6040:     }
6041:   } else {
6042:     const PetscInt **permsF = NULL;
6043:     const PetscInt **permsC = NULL;

6045:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6046:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6047:     for (p = 0, off = 0; p < numFPoints; p++) {
6048:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6050:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6051:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6052:     }
6053:     for (p = 0, off = 0; p < numCPoints; p++) {
6054:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6056:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6057:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6058:     }
6059:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6060:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6061:   }
6062:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
6063:   /* TODO: flips */
6064:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6065:   if (ierr) {
6066:     PetscMPIInt    rank;
6067:     PetscErrorCode ierr2;

6069:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6070:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6071:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6072:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6073:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6074: 
6075:   }
6076:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6077:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6078:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
6079:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
6080:   return(0);
6081: }

6083: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6084: {
6085:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
6086:   PetscInt      *cpoints = NULL;
6087:   PetscInt       foffsets[32], coffsets[32];
6088:   CellRefiner    cellRefiner;
6089:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

6095:   if (!fsection) {DMGetSection(dmf, &fsection);}
6097:   if (!csection) {DMGetSection(dmc, &csection);}
6099:   if (!globalFSection) {DMGetGlobalSection(dmf, &globalFSection);}
6101:   if (!globalCSection) {DMGetGlobalSection(dmc, &globalCSection);}
6103:   PetscSectionGetNumFields(fsection, &numFields);
6104:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6105:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
6106:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
6107:   /* Column indices */
6108:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6109:   maxFPoints = numCPoints;
6110:   /* Compress out points not in the section */
6111:   /*   TODO: Squeeze out points with 0 dof as well */
6112:   PetscSectionGetChart(csection, &pStart, &pEnd);
6113:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6114:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6115:       cpoints[q*2]   = cpoints[p];
6116:       cpoints[q*2+1] = cpoints[p+1];
6117:       ++q;
6118:     }
6119:   }
6120:   numCPoints = q;
6121:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6122:     PetscInt fdof;

6124:     PetscSectionGetDof(csection, cpoints[p], &dof);
6125:     if (!dof) continue;
6126:     for (f = 0; f < numFields; ++f) {
6127:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
6128:       coffsets[f+1] += fdof;
6129:     }
6130:     numCIndices += dof;
6131:   }
6132:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6133:   /* Row indices */
6134:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
6135:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
6136:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
6137:   for (r = 0, q = 0; r < numSubcells; ++r) {
6138:     /* TODO Map from coarse to fine cells */
6139:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
6140:     /* Compress out points not in the section */
6141:     PetscSectionGetChart(fsection, &pStart, &pEnd);
6142:     for (p = 0; p < numFPoints*2; p += 2) {
6143:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6144:         PetscSectionGetDof(fsection, fpoints[p], &dof);
6145:         if (!dof) continue;
6146:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6147:         if (s < q) continue;
6148:         ftotpoints[q*2]   = fpoints[p];
6149:         ftotpoints[q*2+1] = fpoints[p+1];
6150:         ++q;
6151:       }
6152:     }
6153:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
6154:   }
6155:   numFPoints = q;
6156:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6157:     PetscInt fdof;

6159:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
6160:     if (!dof) continue;
6161:     for (f = 0; f < numFields; ++f) {
6162:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
6163:       foffsets[f+1] += fdof;
6164:     }
6165:     numFIndices += dof;
6166:   }
6167:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

6175:     for (f = 0; f < numFields; f++) {
6176:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6177:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6178:     }
6179:     for (p = 0; p < numFPoints; p++) {
6180:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6181:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
6182:     }
6183:     for (p = 0; p < numCPoints; p++) {
6184:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6185:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
6186:     }
6187:     for (f = 0; f < numFields; f++) {
6188:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
6189:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
6190:     }
6191:   } else {
6192:     const PetscInt **permsF = NULL;
6193:     const PetscInt **permsC = NULL;

6195:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6196:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6197:     for (p = 0, off = 0; p < numFPoints; p++) {
6198:       const PetscInt *perm = permsF ? permsF[p] : NULL;

6200:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
6201:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6202:     }
6203:     for (p = 0, off = 0; p < numCPoints; p++) {
6204:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6206:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6207:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6208:     }
6209:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6210:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6211:   }
6212:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6213:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6214:   return(0);
6215: }

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

6220:   Input Parameter:
6221: . dm - The DMPlex object

6223:   Output Parameters:
6224: + cMax - The first hybrid cell
6225: . fMax - The first hybrid face
6226: . eMax - The first hybrid edge
6227: - vMax - The first hybrid vertex

6229:   Level: developer

6231: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6232: @*/
6233: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6234: {
6235:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6236:   PetscInt       dim;

6241:   DMGetDimension(dm, &dim);
6242:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6243:   if (cMax) *cMax = mesh->hybridPointMax[dim];
6244:   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6245:   if (eMax) *eMax = mesh->hybridPointMax[1];
6246:   if (vMax) *vMax = mesh->hybridPointMax[0];
6247:   return(0);
6248: }

6250: static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6251: {
6252:   IS             is, his;
6253:   PetscInt       first = 0, stride;
6254:   PetscBool      isStride;

6258:   DMLabelGetStratumIS(depthLabel, d, &is);
6259:   PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);
6260:   if (isStride) {
6261:     ISStrideGetInfo(is, &first, &stride);
6262:   }
6263:   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6264:   ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);
6265:   DMLabelSetStratumIS(dimLabel, d, his);
6266:   ISDestroy(&his);
6267:   ISDestroy(&is);
6268:   return(0);
6269: }

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

6274:   Input Parameters:
6275: . dm   - The DMPlex object
6276: . cMax - The first hybrid cell
6277: . fMax - The first hybrid face
6278: . eMax - The first hybrid edge
6279: - vMax - The first hybrid vertex

6281:   Level: developer

6283: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6284: @*/
6285: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6286: {
6287:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6288:   PetscInt       dim;

6293:   DMGetDimension(dm, &dim);
6294:   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6295:   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6296:   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6297:   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6298:   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6299:   return(0);
6300: }

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

6305:   Input Parameter:
6306: . dm   - The DMPlex object

6308:   Output Parameter:
6309: . cellHeight - The height of a cell

6311:   Level: developer

6313: .seealso DMPlexSetVTKCellHeight()
6314: @*/
6315: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6316: {
6317:   DM_Plex *mesh = (DM_Plex*) dm->data;

6322:   *cellHeight = mesh->vtkCellHeight;
6323:   return(0);
6324: }

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

6329:   Input Parameters:
6330: + dm   - The DMPlex object
6331: - cellHeight - The height of a cell

6333:   Level: developer

6335: .seealso DMPlexGetVTKCellHeight()
6336: @*/
6337: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6338: {
6339:   DM_Plex *mesh = (DM_Plex*) dm->data;

6343:   mesh->vtkCellHeight = cellHeight;
6344:   return(0);
6345: }

6347: /* We can easily have a form that takes an IS instead */
6348: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6349: {
6350:   PetscSection   section, globalSection;
6351:   PetscInt      *numbers, p;

6355:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6356:   PetscSectionSetChart(section, pStart, pEnd);
6357:   for (p = pStart; p < pEnd; ++p) {
6358:     PetscSectionSetDof(section, p, 1);
6359:   }
6360:   PetscSectionSetUp(section);
6361:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6362:   PetscMalloc1(pEnd - pStart, &numbers);
6363:   for (p = pStart; p < pEnd; ++p) {
6364:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6365:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6366:     else                       numbers[p-pStart] += shift;
6367:   }
6368:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6369:   if (globalSize) {
6370:     PetscLayout layout;
6371:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6372:     PetscLayoutGetSize(layout, globalSize);
6373:     PetscLayoutDestroy(&layout);
6374:   }
6375:   PetscSectionDestroy(&section);
6376:   PetscSectionDestroy(&globalSection);
6377:   return(0);
6378: }

6380: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6381: {
6382:   PetscInt       cellHeight, cStart, cEnd, cMax;

6386:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6387:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6388:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6389:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6390:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6391:   return(0);
6392: }

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

6397:   Input Parameter:
6398: . dm   - The DMPlex object

6400:   Output Parameter:
6401: . globalCellNumbers - Global cell numbers for all cells on this process

6403:   Level: developer

6405: .seealso DMPlexGetVertexNumbering()
6406: @*/
6407: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6408: {
6409:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6414:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6415:   *globalCellNumbers = mesh->globalCellNumbers;
6416:   return(0);
6417: }

6419: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6420: {
6421:   PetscInt       vStart, vEnd, vMax;

6426:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6427:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6428:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6429:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6430:   return(0);
6431: }

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

6436:   Input Parameter:
6437: . dm   - The DMPlex object

6439:   Output Parameter:
6440: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6442:   Level: developer

6444: .seealso DMPlexGetCellNumbering()
6445: @*/
6446: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6447: {
6448:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6453:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6454:   *globalVertexNumbers = mesh->globalVertexNumbers;
6455:   return(0);
6456: }

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

6461:   Input Parameter:
6462: . dm   - The DMPlex object

6464:   Output Parameter:
6465: . globalPointNumbers - Global numbers for all points on this process

6467:   Level: developer

6469: .seealso DMPlexGetCellNumbering()
6470: @*/
6471: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6472: {
6473:   IS             nums[4];
6474:   PetscInt       depths[4];
6475:   PetscInt       depth, d, shift = 0;

6480:   DMPlexGetDepth(dm, &depth);
6481:   /* For unstratified meshes use dim instead of depth */
6482:   if (depth < 0) {DMGetDimension(dm, &depth);}
6483:   depths[0] = depth; depths[1] = 0;
6484:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6485:   for (d = 0; d <= depth; ++d) {
6486:     PetscInt pStart, pEnd, gsize;

6488:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6489:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6490:     shift += gsize;
6491:   }
6492:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6493:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6494:   return(0);
6495: }


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

6501:   Input Parameter:
6502: . dm - The DMPlex object

6504:   Output Parameter:
6505: . ranks - The rank field

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

6510:   Level: intermediate

6512: .seealso: DMView()
6513: @*/
6514: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6515: {
6516:   DM             rdm;
6517:   PetscDS        prob;
6518:   PetscFE        fe;
6519:   PetscScalar   *r;
6520:   PetscMPIInt    rank;
6521:   PetscInt       dim, cStart, cEnd, c;

6525:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6526:   DMClone(dm, &rdm);
6527:   DMGetDimension(rdm, &dim);
6528:   PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, NULL, -1, &fe);
6529:   PetscObjectSetName((PetscObject) fe, "rank");
6530:   DMGetDS(rdm, &prob);
6531:   PetscDSSetDiscretization(prob, 0, (PetscObject) fe);
6532:   PetscFEDestroy(&fe);
6533:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6534:   DMCreateGlobalVector(rdm, ranks);
6535:   PetscObjectSetName((PetscObject) *ranks, "partition");
6536:   VecGetArray(*ranks, &r);
6537:   for (c = cStart; c < cEnd; ++c) {
6538:     PetscScalar *lr;

6540:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6541:     *lr = rank;
6542:   }
6543:   VecRestoreArray(*ranks, &r);
6544:   DMDestroy(&rdm);
6545:   return(0);
6546: }

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

6551:   Input Parameter:
6552: . dm - The DMPlex object

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

6556:   Level: developer

6558: .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6559: @*/
6560: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6561: {
6562:   PetscSection    coneSection, supportSection;
6563:   const PetscInt *cone, *support;
6564:   PetscInt        coneSize, c, supportSize, s;
6565:   PetscInt        pStart, pEnd, p, csize, ssize;
6566:   PetscErrorCode  ierr;

6570:   DMPlexGetConeSection(dm, &coneSection);
6571:   DMPlexGetSupportSection(dm, &supportSection);
6572:   /* Check that point p is found in the support of its cone points, and vice versa */
6573:   DMPlexGetChart(dm, &pStart, &pEnd);
6574:   for (p = pStart; p < pEnd; ++p) {
6575:     DMPlexGetConeSize(dm, p, &coneSize);
6576:     DMPlexGetCone(dm, p, &cone);
6577:     for (c = 0; c < coneSize; ++c) {
6578:       PetscBool dup = PETSC_FALSE;
6579:       PetscInt  d;
6580:       for (d = c-1; d >= 0; --d) {
6581:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6582:       }
6583:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6584:       DMPlexGetSupport(dm, cone[c], &support);
6585:       for (s = 0; s < supportSize; ++s) {
6586:         if (support[s] == p) break;
6587:       }
6588:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6589:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6590:         for (s = 0; s < coneSize; ++s) {
6591:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6592:         }
6593:         PetscPrintf(PETSC_COMM_SELF, "\n");
6594:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6595:         for (s = 0; s < supportSize; ++s) {
6596:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6597:         }
6598:         PetscPrintf(PETSC_COMM_SELF, "\n");
6599:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6600:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6601:       }
6602:     }
6603:     DMPlexGetSupportSize(dm, p, &supportSize);
6604:     DMPlexGetSupport(dm, p, &support);
6605:     for (s = 0; s < supportSize; ++s) {
6606:       DMPlexGetConeSize(dm, support[s], &coneSize);
6607:       DMPlexGetCone(dm, support[s], &cone);
6608:       for (c = 0; c < coneSize; ++c) {
6609:         if (cone[c] == p) break;
6610:       }
6611:       if (c >= coneSize) {
6612:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6613:         for (c = 0; c < supportSize; ++c) {
6614:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6615:         }
6616:         PetscPrintf(PETSC_COMM_SELF, "\n");
6617:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6618:         for (c = 0; c < coneSize; ++c) {
6619:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6620:         }
6621:         PetscPrintf(PETSC_COMM_SELF, "\n");
6622:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6623:       }
6624:     }
6625:   }
6626:   PetscSectionGetStorageSize(coneSection, &csize);
6627:   PetscSectionGetStorageSize(supportSection, &ssize);
6628:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6629:   return(0);
6630: }

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

6635:   Input Parameters:
6636: + dm - The DMPlex object
6637: . isSimplex - Are the cells simplices or tensor products
6638: - cellHeight - Normally 0

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

6642:   Level: developer

6644: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6645: @*/
6646: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6647: {
6648:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6653:   DMGetDimension(dm, &dim);
6654:   switch (dim) {
6655:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6656:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6657:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6658:   default:
6659:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6660:   }
6661:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6662:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6663:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6664:   cMax = cMax >= 0 ? cMax : cEnd;
6665:   for (c = cStart; c < cMax; ++c) {
6666:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6668:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6669:     for (cl = 0; cl < closureSize*2; cl += 2) {
6670:       const PetscInt p = closure[cl];
6671:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6672:     }
6673:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6674:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6675:   }
6676:   for (c = cMax; c < cEnd; ++c) {
6677:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6679:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6680:     for (cl = 0; cl < closureSize*2; cl += 2) {
6681:       const PetscInt p = closure[cl];
6682:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6683:     }
6684:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6685:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6686:   }
6687:   return(0);
6688: }

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

6693:   Input Parameters:
6694: + dm - The DMPlex object
6695: . isSimplex - Are the cells simplices or tensor products
6696: - cellHeight - Normally 0

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

6700:   Level: developer

6702: .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6703: @*/
6704: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6705: {
6706:   PetscInt       pMax[4];
6707:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

6712:   DMGetDimension(dm, &dim);
6713:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6714:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6715:   for (h = cellHeight; h < dim; ++h) {
6716:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6717:     for (c = cStart; c < cEnd; ++c) {
6718:       const PetscInt *cone, *ornt, *faces;
6719:       PetscInt        numFaces, faceSize, coneSize,f;
6720:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6722:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6723:       DMPlexGetConeSize(dm, c, &coneSize);
6724:       DMPlexGetCone(dm, c, &cone);
6725:       DMPlexGetConeOrientation(dm, c, &ornt);
6726:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6727:       for (cl = 0; cl < closureSize*2; cl += 2) {
6728:         const PetscInt p = closure[cl];
6729:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6730:       }
6731:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6732:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6733:       for (f = 0; f < numFaces; ++f) {
6734:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6736:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6737:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6738:           const PetscInt p = fclosure[cl];
6739:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6740:         }
6741:         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);
6742:         for (v = 0; v < fnumCorners; ++v) {
6743:           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]);
6744:         }
6745:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6746:       }
6747:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6748:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6749:     }
6750:   }
6751:   return(0);
6752: }

6754: /* Pointwise interpolation
6755:      Just code FEM for now
6756:      u^f = I u^c
6757:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6758:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6759:      I_{ij} = psi^f_i phi^c_j
6760: */
6761: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6762: {
6763:   PetscSection   gsc, gsf;
6764:   PetscInt       m, n;
6765:   void          *ctx;
6766:   DM             cdm;
6767:   PetscBool      regular, ismatis;

6771:   DMGetGlobalSection(dmFine, &gsf);
6772:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6773:   DMGetGlobalSection(dmCoarse, &gsc);
6774:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6776:   PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);
6777:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6778:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6779:   MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);
6780:   DMGetApplicationContext(dmFine, &ctx);

6782:   DMGetCoarseDM(dmFine, &cdm);
6783:   DMPlexGetRegularRefinement(dmFine, &regular);
6784:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6785:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6786:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6787:   /* Use naive scaling */
6788:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6789:   return(0);
6790: }

6792: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6793: {
6795:   VecScatter     ctx;

6798:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6799:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6800:   VecScatterDestroy(&ctx);
6801:   return(0);
6802: }

6804: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6805: {
6806:   PetscSection   gsc, gsf;
6807:   PetscInt       m, n;
6808:   void          *ctx;
6809:   DM             cdm;
6810:   PetscBool      regular;

6814:   DMGetGlobalSection(dmFine, &gsf);
6815:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6816:   DMGetGlobalSection(dmCoarse, &gsc);
6817:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6819:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
6820:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6821:   MatSetType(*mass, dmCoarse->mattype);
6822:   DMGetApplicationContext(dmFine, &ctx);

6824:   DMGetCoarseDM(dmFine, &cdm);
6825:   DMPlexGetRegularRefinement(dmFine, &regular);
6826:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
6827:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
6828:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
6829:   return(0);
6830: }

6832: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6833: {
6834:   PetscSection   section;
6835:   IS            *bcPoints, *bcComps;
6836:   PetscBool     *isFE;
6837:   PetscInt      *bcFields, *numComp, *numDof;
6838:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6839:   PetscInt       cStart, cEnd, cEndInterior;

6843:   DMGetNumFields(dm, &numFields);
6844:   /* FE and FV boundary conditions are handled slightly differently */
6845:   PetscMalloc1(numFields, &isFE);
6846:   for (f = 0; f < numFields; ++f) {
6847:     PetscObject  obj;
6848:     PetscClassId id;

6850:     DMGetField(dm, f, &obj);
6851:     PetscObjectGetClassId(obj, &id);
6852:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6853:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6854:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6855:   }
6856:   /* Allocate boundary point storage for FEM boundaries */
6857:   DMPlexGetDepth(dm, &depth);
6858:   DMGetDimension(dm, &dim);
6859:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6860:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6861:   PetscDSGetNumBoundary(dm->prob, &numBd);
6862:   if (!numFields && numBd) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "number of fields is zero and number of boundary conditions is nonzero (this should never happen)");
6863:   for (bd = 0; bd < numBd; ++bd) {
6864:     PetscInt                field;
6865:     DMBoundaryConditionType type;
6866:     const char             *labelName;
6867:     DMLabel                 label;

6869:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6870:     DMGetLabel(dm,labelName,&label);
6871:     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6872:   }
6873:   /* Add ghost cell boundaries for FVM */
6874:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6875:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6876:   /* Constrain ghost cells for FV */
6877:   for (f = 0; f < numFields; ++f) {
6878:     PetscInt *newidx, c;

6880:     if (isFE[f] || cEndInterior < 0) continue;
6881:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6882:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6883:     bcFields[bc] = f;
6884:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6885:   }
6886:   /* Handle FEM Dirichlet boundaries */
6887:   for (bd = 0; bd < numBd; ++bd) {
6888:     const char             *bdLabel;
6889:     DMLabel                 label;
6890:     const PetscInt         *comps;
6891:     const PetscInt         *values;
6892:     PetscInt                bd2, field, numComps, numValues;
6893:     DMBoundaryConditionType type;
6894:     PetscBool               duplicate = PETSC_FALSE;

6896:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6897:     DMGetLabel(dm, bdLabel, &label);
6898:     if (!isFE[field] || !label) continue;
6899:     /* Only want to modify label once */
6900:     for (bd2 = 0; bd2 < bd; ++bd2) {
6901:       const char *bdname;
6902:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6903:       PetscStrcmp(bdname, bdLabel, &duplicate);
6904:       if (duplicate) break;
6905:     }
6906:     if (!duplicate && (isFE[field])) {
6907:       /* don't complete cells, which are just present to give orientation to the boundary */
6908:       DMPlexLabelComplete(dm, label);
6909:     }
6910:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6911:     if (type & DM_BC_ESSENTIAL) {
6912:       PetscInt       *newidx;
6913:       PetscInt        n, newn = 0, p, v;

6915:       bcFields[bc] = field;
6916:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6917:       for (v = 0; v < numValues; ++v) {
6918:         IS              tmp;
6919:         const PetscInt *idx;

6921:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6922:         if (!tmp) continue;
6923:         ISGetLocalSize(tmp, &n);
6924:         ISGetIndices(tmp, &idx);
6925:         if (isFE[field]) {
6926:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6927:         } else {
6928:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6929:         }
6930:         ISRestoreIndices(tmp, &idx);
6931:         ISDestroy(&tmp);
6932:       }
6933:       PetscMalloc1(newn,&newidx);
6934:       newn = 0;
6935:       for (v = 0; v < numValues; ++v) {
6936:         IS              tmp;
6937:         const PetscInt *idx;

6939:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6940:         if (!tmp) continue;
6941:         ISGetLocalSize(tmp, &n);
6942:         ISGetIndices(tmp, &idx);
6943:         if (isFE[field]) {
6944:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6945:         } else {
6946:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6947:         }
6948:         ISRestoreIndices(tmp, &idx);
6949:         ISDestroy(&tmp);
6950:       }
6951:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6952:     }
6953:   }
6954:   /* Handle discretization */
6955:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6956:   for (f = 0; f < numFields; ++f) {
6957:     PetscObject obj;

6959:     DMGetField(dm, f, &obj);
6960:     if (isFE[f]) {
6961:       PetscFE         fe = (PetscFE) obj;
6962:       const PetscInt *numFieldDof;
6963:       PetscInt        d;

6965:       PetscFEGetNumComponents(fe, &numComp[f]);
6966:       PetscFEGetNumDof(fe, &numFieldDof);
6967:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6968:     } else {
6969:       PetscFV fv = (PetscFV) obj;

6971:       PetscFVGetNumComponents(fv, &numComp[f]);
6972:       numDof[f*(dim+1)+dim] = numComp[f];
6973:     }
6974:   }
6975:   for (f = 0; f < numFields; ++f) {
6976:     PetscInt d;
6977:     for (d = 1; d < dim; ++d) {
6978:       if ((numDof[f*(dim+1)+d] > 0) && (depth < dim)) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated when unknowns are specified on edges or faces.");
6979:     }
6980:   }
6981:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6982:   for (f = 0; f < numFields; ++f) {
6983:     PetscFE     fe;
6984:     const char *name;

6986:     DMGetField(dm, f, (PetscObject *) &fe);
6987:     PetscObjectGetName((PetscObject) fe, &name);
6988:     PetscSectionSetFieldName(section, f, name);
6989:   }
6990:   DMSetSection(dm, section);
6991:   PetscSectionDestroy(&section);
6992:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6993:   PetscFree3(bcFields,bcPoints,bcComps);
6994:   PetscFree2(numComp,numDof);
6995:   PetscFree(isFE);
6996:   return(0);
6997: }

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

7002:   Input Parameter:
7003: . dm - The DMPlex object

7005:   Output Parameter:
7006: . regular - The flag

7008:   Level: intermediate

7010: .seealso: DMPlexSetRegularRefinement()
7011: @*/
7012: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7013: {
7017:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
7018:   return(0);
7019: }

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

7024:   Input Parameters:
7025: + dm - The DMPlex object
7026: - regular - The flag

7028:   Level: intermediate

7030: .seealso: DMPlexGetRegularRefinement()
7031: @*/
7032: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7033: {
7036:   ((DM_Plex *) dm->data)->regularRefinement = regular;
7037:   return(0);
7038: }

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

7045:   not collective

7047:   Input Parameters:
7048: . dm - The DMPlex object

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


7055:   Level: intermediate

7057: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7058: @*/
7059: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7060: {
7061:   DM_Plex *plex = (DM_Plex *)dm->data;

7066:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
7067:   if (anchorSection) *anchorSection = plex->anchorSection;
7068:   if (anchorIS) *anchorIS = plex->anchorIS;
7069:   return(0);
7070: }

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

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

7080:   collective on dm

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

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

7089:   Level: intermediate

7091: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7092: @*/
7093: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7094: {
7095:   DM_Plex        *plex = (DM_Plex *)dm->data;
7096:   PetscMPIInt    result;

7101:   if (anchorSection) {
7103:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
7104:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7105:   }
7106:   if (anchorIS) {
7108:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
7109:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7110:   }

7112:   PetscObjectReference((PetscObject)anchorSection);
7113:   PetscSectionDestroy(&plex->anchorSection);
7114:   plex->anchorSection = anchorSection;

7116:   PetscObjectReference((PetscObject)anchorIS);
7117:   ISDestroy(&plex->anchorIS);
7118:   plex->anchorIS = anchorIS;

7120: #if defined(PETSC_USE_DEBUG)
7121:   if (anchorIS && anchorSection) {
7122:     PetscInt size, a, pStart, pEnd;
7123:     const PetscInt *anchors;

7125:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7126:     ISGetLocalSize(anchorIS,&size);
7127:     ISGetIndices(anchorIS,&anchors);
7128:     for (a = 0; a < size; a++) {
7129:       PetscInt p;

7131:       p = anchors[a];
7132:       if (p >= pStart && p < pEnd) {
7133:         PetscInt dof;

7135:         PetscSectionGetDof(anchorSection,p,&dof);
7136:         if (dof) {
7137:           PetscErrorCode ierr2;

7139:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7140:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7141:         }
7142:       }
7143:     }
7144:     ISRestoreIndices(anchorIS,&anchors);
7145:   }
7146: #endif
7147:   /* reset the generic constraints */
7148:   DMSetDefaultConstraints(dm,NULL,NULL);
7149:   return(0);
7150: }

7152: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7153: {
7154:   PetscSection anchorSection;
7155:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

7160:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7161:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
7162:   PetscSectionGetNumFields(section,&numFields);
7163:   if (numFields) {
7164:     PetscInt f;
7165:     PetscSectionSetNumFields(*cSec,numFields);

7167:     for (f = 0; f < numFields; f++) {
7168:       PetscInt numComp;

7170:       PetscSectionGetFieldComponents(section,f,&numComp);
7171:       PetscSectionSetFieldComponents(*cSec,f,numComp);
7172:     }
7173:   }
7174:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
7175:   PetscSectionGetChart(section,&sStart,&sEnd);
7176:   pStart = PetscMax(pStart,sStart);
7177:   pEnd   = PetscMin(pEnd,sEnd);
7178:   pEnd   = PetscMax(pStart,pEnd);
7179:   PetscSectionSetChart(*cSec,pStart,pEnd);
7180:   for (p = pStart; p < pEnd; p++) {
7181:     PetscSectionGetDof(anchorSection,p,&dof);
7182:     if (dof) {
7183:       PetscSectionGetDof(section,p,&dof);
7184:       PetscSectionSetDof(*cSec,p,dof);
7185:       for (f = 0; f < numFields; f++) {
7186:         PetscSectionGetFieldDof(section,p,f,&dof);
7187:         PetscSectionSetFieldDof(*cSec,p,f,dof);
7188:       }
7189:     }
7190:   }
7191:   PetscSectionSetUp(*cSec);
7192:   return(0);
7193: }

7195: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7196: {
7197:   PetscSection aSec;
7198:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7199:   const PetscInt *anchors;
7200:   PetscInt numFields, f;
7201:   IS aIS;

7206:   PetscSectionGetStorageSize(cSec, &m);
7207:   PetscSectionGetStorageSize(section, &n);
7208:   MatCreate(PETSC_COMM_SELF,cMat);
7209:   MatSetSizes(*cMat,m,n,m,n);
7210:   MatSetType(*cMat,MATSEQAIJ);
7211:   DMPlexGetAnchors(dm,&aSec,&aIS);
7212:   ISGetIndices(aIS,&anchors);
7213:   /* cSec will be a subset of aSec and section */
7214:   PetscSectionGetChart(cSec,&pStart,&pEnd);
7215:   PetscMalloc1(m+1,&i);
7216:   i[0] = 0;
7217:   PetscSectionGetNumFields(section,&numFields);
7218:   for (p = pStart; p < pEnd; p++) {
7219:     PetscInt rDof, rOff, r;

7221:     PetscSectionGetDof(aSec,p,&rDof);
7222:     if (!rDof) continue;
7223:     PetscSectionGetOffset(aSec,p,&rOff);
7224:     if (numFields) {
7225:       for (f = 0; f < numFields; f++) {
7226:         annz = 0;
7227:         for (r = 0; r < rDof; r++) {
7228:           a = anchors[rOff + r];
7229:           PetscSectionGetFieldDof(section,a,f,&aDof);
7230:           annz += aDof;
7231:         }
7232:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7233:         PetscSectionGetFieldOffset(cSec,p,f,&off);
7234:         for (q = 0; q < dof; q++) {
7235:           i[off + q + 1] = i[off + q] + annz;
7236:         }
7237:       }
7238:     }
7239:     else {
7240:       annz = 0;
7241:       for (q = 0; q < dof; q++) {
7242:         a = anchors[off + q];
7243:         PetscSectionGetDof(section,a,&aDof);
7244:         annz += aDof;
7245:       }
7246:       PetscSectionGetDof(cSec,p,&dof);
7247:       PetscSectionGetOffset(cSec,p,&off);
7248:       for (q = 0; q < dof; q++) {
7249:         i[off + q + 1] = i[off + q] + annz;
7250:       }
7251:     }
7252:   }
7253:   nnz = i[m];
7254:   PetscMalloc1(nnz,&j);
7255:   offset = 0;
7256:   for (p = pStart; p < pEnd; p++) {
7257:     if (numFields) {
7258:       for (f = 0; f < numFields; f++) {
7259:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7260:         for (q = 0; q < dof; q++) {
7261:           PetscInt rDof, rOff, r;
7262:           PetscSectionGetDof(aSec,p,&rDof);
7263:           PetscSectionGetOffset(aSec,p,&rOff);
7264:           for (r = 0; r < rDof; r++) {
7265:             PetscInt s;

7267:             a = anchors[rOff + r];
7268:             PetscSectionGetFieldDof(section,a,f,&aDof);
7269:             PetscSectionGetFieldOffset(section,a,f,&aOff);
7270:             for (s = 0; s < aDof; s++) {
7271:               j[offset++] = aOff + s;
7272:             }
7273:           }
7274:         }
7275:       }
7276:     }
7277:     else {
7278:       PetscSectionGetDof(cSec,p,&dof);
7279:       for (q = 0; q < dof; q++) {
7280:         PetscInt rDof, rOff, r;
7281:         PetscSectionGetDof(aSec,p,&rDof);
7282:         PetscSectionGetOffset(aSec,p,&rOff);
7283:         for (r = 0; r < rDof; r++) {
7284:           PetscInt s;

7286:           a = anchors[rOff + r];
7287:           PetscSectionGetDof(section,a,&aDof);
7288:           PetscSectionGetOffset(section,a,&aOff);
7289:           for (s = 0; s < aDof; s++) {
7290:             j[offset++] = aOff + s;
7291:           }
7292:         }
7293:       }
7294:     }
7295:   }
7296:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7297:   PetscFree(i);
7298:   PetscFree(j);
7299:   ISRestoreIndices(aIS,&anchors);
7300:   return(0);
7301: }

7303: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7304: {
7305:   DM_Plex        *plex = (DM_Plex *)dm->data;
7306:   PetscSection   anchorSection, section, cSec;
7307:   Mat            cMat;

7312:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7313:   if (anchorSection) {
7314:     PetscDS  ds;
7315:     PetscInt nf;

7317:     DMGetSection(dm,&section);
7318:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7319:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7320:     DMGetDS(dm,&ds);
7321:     PetscDSGetNumFields(ds,&nf);
7322:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7323:     DMSetDefaultConstraints(dm,cSec,cMat);
7324:     PetscSectionDestroy(&cSec);
7325:     MatDestroy(&cMat);
7326:   }
7327:   return(0);
7328: }

7330: PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7331: {
7332:   PetscDS        prob;
7333:   IS             subis;
7334:   PetscSection   section, subsection;

7338:   DMGetDefaultSection(dm, &section);
7339:   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7340:   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7341:   /* Create subdomain */
7342:   DMPlexFilter(dm, label, value, subdm);
7343:   /* Create submodel */
7344:   DMPlexCreateSubpointIS(*subdm, &subis);
7345:   PetscSectionCreateSubmeshSection(section, subis, &subsection);
7346:   ISDestroy(&subis);
7347:   DMSetDefaultSection(*subdm, subsection);
7348:   PetscSectionDestroy(&subsection);
7349:   DMGetDS(dm, &prob);
7350:   DMSetDS(*subdm, prob);
7351:   /* Create map from submodel to global model */
7352:   if (is) {
7353:     PetscSection    sectionGlobal, subsectionGlobal;
7354:     IS              spIS;
7355:     const PetscInt *spmap;
7356:     PetscInt       *subIndices;
7357:     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
7358:     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];

7360:     DMPlexCreateSubpointIS(*subdm, &spIS);
7361:     ISGetIndices(spIS, &spmap);
7362:     PetscSectionGetNumFields(section, &Nf);
7363:     DMGetDefaultGlobalSection(dm, &sectionGlobal);
7364:     DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);
7365:     PetscSectionGetChart(subsection, &pStart, &pEnd);
7366:     for (p = pStart; p < pEnd; ++p) {
7367:       PetscInt gdof, pSubSize  = 0;

7369:       PetscSectionGetDof(sectionGlobal, p, &gdof);
7370:       if (gdof > 0) {
7371:         for (f = 0; f < Nf; ++f) {
7372:           PetscInt fdof, fcdof;

7374:           PetscSectionGetFieldDof(subsection, p, f, &fdof);
7375:           PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);
7376:           pSubSize += fdof-fcdof;
7377:         }
7378:         subSize += pSubSize;
7379:         if (pSubSize) {
7380:           if (bs < 0) {
7381:             bs = pSubSize;
7382:           } else if (bs != pSubSize) {
7383:             /* Layout does not admit a pointwise block size */
7384:             bs = 1;
7385:           }
7386:         }
7387:       }
7388:     }
7389:     /* Must have same blocksize on all procs (some might have no points) */
7390:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7391:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
7392:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7393:     else                            {bs = bsMinMax[0];}
7394:     PetscMalloc1(subSize, &subIndices);
7395:     for (p = pStart; p < pEnd; ++p) {
7396:       PetscInt gdof, goff;

7398:       PetscSectionGetDof(subsectionGlobal, p, &gdof);
7399:       if (gdof > 0) {
7400:         const PetscInt point = spmap[p];

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

7406:           /* Can get rid of this loop by storing field information in the global section */
7407:           for (f2 = 0; f2 < f; ++f2) {
7408:             PetscSectionGetFieldDof(section, p, f2, &fdof);
7409:             PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
7410:             poff += fdof-fcdof;
7411:           }
7412:           PetscSectionGetFieldDof(section, p, f, &fdof);
7413:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
7414:           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7415:             subIndices[subOff] = goff+poff+fc;
7416:           }
7417:         }
7418:       }
7419:     }
7420:     ISRestoreIndices(spIS, &spmap);
7421:     ISDestroy(&spIS);
7422:     ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);
7423:     if (bs > 1) {
7424:       /* We need to check that the block size does not come from non-contiguous fields */
7425:       PetscInt i, j, set = 1;
7426:       for (i = 0; i < subSize; i += bs) {
7427:         for (j = 0; j < bs; ++j) {
7428:           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7429:         }
7430:       }
7431:       if (set) {ISSetBlockSize(*is, bs);}
7432:     }
7433:     /* Attach nullspace */
7434:     for (f = 0; f < Nf; ++f) {
7435:       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7436:       if ((*subdm)->nullspaceConstructors[f]) break;
7437:     }
7438:     if (f < Nf) {
7439:       MatNullSpace nullSpace;

7441:       (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);
7442:       PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
7443:       MatNullSpaceDestroy(&nullSpace);
7444:     }
7445:   }
7446:   return(0);
7447: }