Actual source code: plex.c

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

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

 11: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

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

 17:   Collective

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

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

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

 27:   Level: intermediate

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

960:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
961:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
962:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
963:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
964:   if (iascii) {
965:     DMPlexView_Ascii(dm, viewer);
966:   } else if (ishdf5) {
967: #if defined(PETSC_HAVE_HDF5)
968:     PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
969:     DMPlexView_HDF5_Internal(dm, viewer);
970:     PetscViewerPopFormat(viewer);
971: #else
972:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
973: #endif
974:   } else if (isvtk) {
975:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
976:   } else if (isdraw) {
977:     DMPlexView_Draw(dm, viewer);
978:   }
979:   /* Optionally view the partition */
980:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
981:   if (flg) {
982:     Vec ranks;
983:     DMPlexCreateRankField(dm, &ranks);
984:     VecView(ranks, viewer);
985:     VecDestroy(&ranks);
986:   }
987:   return(0);
988: }

990: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
991: {
992:   PetscBool      isbinary, ishdf5;

998:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
999:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
1000:   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
1001:   else if (ishdf5) {
1002: #if defined(PETSC_HAVE_HDF5)
1003:     DMPlexLoad_HDF5_Internal(dm, viewer);
1004: #else
1005:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1006: #endif
1007:   }
1008:   return(0);
1009: }

1011: PetscErrorCode DMDestroy_Plex(DM dm)
1012: {
1013:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1046: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1047: {
1048:   PetscSection           sectionGlobal;
1049:   PetscInt               bs = -1, mbs;
1050:   PetscInt               localSize;
1051:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1052:   PetscErrorCode         ierr;
1053:   MatType                mtype;
1054:   ISLocalToGlobalMapping ltog;

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

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

1087:       DMGetDefaultSection(dm, &section);
1088:       PetscSectionGetStorageSize(section, &size);
1089:       PetscMalloc1(size,&ltogidx);
1090:       DMPlexGetSubdomainSection(dm, &subSection);
1091:     } else {
1092:       DMGetLocalToGlobalMapping(dm,&ltog);
1093:     }
1094:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1095:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1096:       PetscInt bdof;

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

1139: /*@
1140:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1142:   Not collective

1144:   Input Parameter:
1145: . mesh - The DMPlex

1147:   Output Parameters:
1148: . subsection - The subdomain section

1150:   Level: developer

1152: .seealso:
1153: @*/
1154: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1155: {
1156:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1161:   if (!mesh->subdomainSection) {
1162:     PetscSection section;
1163:     PetscSF      sf;

1165:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1166:     DMGetDefaultSection(dm,&section);
1167:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1168:     PetscSFDestroy(&sf);
1169:   }
1170:   *subsection = mesh->subdomainSection;
1171:   return(0);
1172: }

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

1177:   Not collective

1179:   Input Parameter:
1180: . mesh - The DMPlex

1182:   Output Parameters:
1183: + pStart - The first mesh point
1184: - pEnd   - The upper bound for mesh points

1186:   Level: beginner

1188: .seealso: DMPlexCreate(), DMPlexSetChart()
1189: @*/
1190: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1191: {
1192:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1197:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1198:   return(0);
1199: }

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

1204:   Not collective

1206:   Input Parameters:
1207: + mesh - The DMPlex
1208: . pStart - The first mesh point
1209: - pEnd   - The upper bound for mesh points

1211:   Output Parameters:

1213:   Level: beginner

1215: .seealso: DMPlexCreate(), DMPlexGetChart()
1216: @*/
1217: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1218: {
1219:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1224:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1225:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1226:   return(0);
1227: }

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

1232:   Not collective

1234:   Input Parameters:
1235: + mesh - The DMPlex
1236: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1238:   Output Parameter:
1239: . size - The cone size for point p

1241:   Level: beginner

1243: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1244: @*/
1245: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1246: {
1247:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1253:   PetscSectionGetDof(mesh->coneSection, p, size);
1254:   return(0);
1255: }

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

1260:   Not collective

1262:   Input Parameters:
1263: + mesh - The DMPlex
1264: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1265: - size - The cone size for point p

1267:   Output Parameter:

1269:   Note:
1270:   This should be called after DMPlexSetChart().

1272:   Level: beginner

1274: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1275: @*/
1276: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1277: {
1278:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1285:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1286:   return(0);
1287: }

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

1292:   Not collective

1294:   Input Parameters:
1295: + mesh - The DMPlex
1296: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1297: - size - The additional cone size for point p

1299:   Output Parameter:

1301:   Note:
1302:   This should be called after DMPlexSetChart().

1304:   Level: beginner

1306: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1307: @*/
1308: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1309: {
1310:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1311:   PetscInt       csize;

1316:   PetscSectionAddDof(mesh->coneSection, p, size);
1317:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1319:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1320:   return(0);
1321: }

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

1326:   Not collective

1328:   Input Parameters:
1329: + mesh - The DMPlex
1330: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1335:   Level: beginner

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

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

1343: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1344: @*/
1345: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1346: {
1347:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1348:   PetscInt       off;

1354:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1355:   *cone = &mesh->cones[off];
1356:   return(0);
1357: }

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

1362:   Not collective

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

1369:   Output Parameter:

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

1374:   Level: beginner

1376: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1377: @*/
1378: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1379: {
1380:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1381:   PetscInt       pStart, pEnd;
1382:   PetscInt       dof, off, c;

1387:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1388:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1390:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1391:   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);
1392:   for (c = 0; c < dof; ++c) {
1393:     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);
1394:     mesh->cones[off+c] = cone[c];
1395:   }
1396:   return(0);
1397: }

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

1402:   Not collective

1404:   Input Parameters:
1405: + mesh - The DMPlex
1406: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1414:   Level: beginner

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

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

1422: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1423: @*/
1424: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1425: {
1426:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1427:   PetscInt       off;

1432: #if defined(PETSC_USE_DEBUG)
1433:   {
1434:     PetscInt dof;
1435:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1437:   }
1438: #endif
1439:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1441:   *coneOrientation = &mesh->coneOrientations[off];
1442:   return(0);
1443: }

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

1448:   Not collective

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

1458:   Output Parameter:

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

1463:   Level: beginner

1465: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1466: @*/
1467: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1468: {
1469:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1470:   PetscInt       pStart, pEnd;
1471:   PetscInt       dof, off, c;

1476:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1477:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1479:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1480:   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);
1481:   for (c = 0; c < dof; ++c) {
1482:     PetscInt cdof, o = coneOrientation[c];

1484:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1485:     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);
1486:     mesh->coneOrientations[off+c] = o;
1487:   }
1488:   return(0);
1489: }

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

1494:   Not collective

1496:   Input Parameters:
1497: + mesh - The DMPlex
1498: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1499: . conePos - The local index in the cone where the point should be put
1500: - conePoint - The mesh point to insert

1502:   Level: beginner

1504: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1505: @*/
1506: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1507: {
1508:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1509:   PetscInt       pStart, pEnd;
1510:   PetscInt       dof, off;

1515:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1516:   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);
1517:   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);
1518:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1519:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1520:   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);
1521:   mesh->cones[off+conePos] = conePoint;
1522:   return(0);
1523: }

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

1528:   Not collective

1530:   Input Parameters:
1531: + mesh - The DMPlex
1532: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1533: . conePos - The local index in the cone where the point should be put
1534: - coneOrientation - The point orientation to insert

1536:   Level: beginner

1538: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1539: @*/
1540: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1541: {
1542:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1543:   PetscInt       pStart, pEnd;
1544:   PetscInt       dof, off;

1549:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1550:   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);
1551:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1552:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1553:   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);
1554:   mesh->coneOrientations[off+conePos] = coneOrientation;
1555:   return(0);
1556: }

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

1561:   Not collective

1563:   Input Parameters:
1564: + mesh - The DMPlex
1565: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

1567:   Output Parameter:
1568: . size - The support size for point p

1570:   Level: beginner

1572: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1573: @*/
1574: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1575: {
1576:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1582:   PetscSectionGetDof(mesh->supportSection, p, size);
1583:   return(0);
1584: }

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

1589:   Not collective

1591:   Input Parameters:
1592: + mesh - The DMPlex
1593: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1594: - size - The support size for point p

1596:   Output Parameter:

1598:   Note:
1599:   This should be called after DMPlexSetChart().

1601:   Level: beginner

1603: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1604: @*/
1605: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1606: {
1607:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1614:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1615:   return(0);
1616: }

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

1621:   Not collective

1623:   Input Parameters:
1624: + mesh - The DMPlex
1625: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

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

1630:   Level: beginner

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

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

1638: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1639: @*/
1640: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1641: {
1642:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1643:   PetscInt       off;

1649:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1650:   *support = &mesh->supports[off];
1651:   return(0);
1652: }

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

1657:   Not collective

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

1664:   Output Parameter:

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

1669:   Level: beginner

1671: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1672: @*/
1673: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1674: {
1675:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1676:   PetscInt       pStart, pEnd;
1677:   PetscInt       dof, off, c;

1682:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1683:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1685:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1686:   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);
1687:   for (c = 0; c < dof; ++c) {
1688:     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);
1689:     mesh->supports[off+c] = support[c];
1690:   }
1691:   return(0);
1692: }

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

1697:   Not collective

1699:   Input Parameters:
1700: + mesh - The DMPlex
1701: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1702: . supportPos - The local index in the cone where the point should be put
1703: - supportPoint - The mesh point to insert

1705:   Level: beginner

1707: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1708: @*/
1709: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1710: {
1711:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1712:   PetscInt       pStart, pEnd;
1713:   PetscInt       dof, off;

1718:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1719:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1720:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1721:   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);
1722:   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);
1723:   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);
1724:   mesh->supports[off+supportPos] = supportPoint;
1725:   return(0);
1726: }

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

1731:   Not collective

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

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

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

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

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

1752:   Level: beginner

1754: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1755: @*/
1756: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1757: {
1758:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1759:   PetscInt       *closure, *fifo;
1760:   const PetscInt *tmp = NULL, *tmpO = NULL;
1761:   PetscInt        tmpSize, t;
1762:   PetscInt        depth       = 0, maxSize;
1763:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1764:   PetscErrorCode  ierr;

1768:   DMPlexGetDepth(dm, &depth);
1769:   /* This is only 1-level */
1770:   if (useCone) {
1771:     DMPlexGetConeSize(dm, p, &tmpSize);
1772:     DMPlexGetCone(dm, p, &tmp);
1773:     DMPlexGetConeOrientation(dm, p, &tmpO);
1774:   } else {
1775:     DMPlexGetSupportSize(dm, p, &tmpSize);
1776:     DMPlexGetSupport(dm, p, &tmp);
1777:   }
1778:   if (depth == 1) {
1779:     if (*points) {
1780:       closure = *points;
1781:     } else {
1782:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1783:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1784:     }
1785:     closure[0] = p; closure[1] = 0;
1786:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1787:       closure[closureSize]   = tmp[t];
1788:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1789:     }
1790:     if (numPoints) *numPoints = closureSize/2;
1791:     if (points)    *points    = closure;
1792:     return(0);
1793:   }
1794:   {
1795:     PetscInt c, coneSeries, s,supportSeries;

1797:     c = mesh->maxConeSize;
1798:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1799:     s = mesh->maxSupportSize;
1800:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1801:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1802:   }
1803:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1804:   if (*points) {
1805:     closure = *points;
1806:   } else {
1807:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1808:   }
1809:   closure[0] = p; closure[1] = 0;
1810:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1811:     const PetscInt cp = tmp[t];
1812:     const PetscInt co = tmpO ? tmpO[t] : 0;

1814:     closure[closureSize]   = cp;
1815:     closure[closureSize+1] = co;
1816:     fifo[fifoSize]         = cp;
1817:     fifo[fifoSize+1]       = co;
1818:   }
1819:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1820:   while (fifoSize - fifoStart) {
1821:     const PetscInt q   = fifo[fifoStart];
1822:     const PetscInt o   = fifo[fifoStart+1];
1823:     const PetscInt rev = o >= 0 ? 0 : 1;
1824:     const PetscInt off = rev ? -(o+1) : o;

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

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

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

1874:   Not collective

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

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

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

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

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

1896:   Level: beginner

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

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

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

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

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

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

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

2026:   Not collective

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

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

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

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

2044:   Level: beginner

2046: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2047: @*/
2048: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2049: {

2056:   DMRestoreWorkArray(dm, 0, PETSC_INT, points);
2057:   if (numPoints) *numPoints = 0;
2058:   return(0);
2059: }

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

2064:   Not collective

2066:   Input Parameter:
2067: . mesh - The DMPlex

2069:   Output Parameters:
2070: + maxConeSize - The maximum number of in-edges
2071: - maxSupportSize - The maximum number of out-edges

2073:   Level: beginner

2075: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2076: @*/
2077: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2078: {
2079:   DM_Plex *mesh = (DM_Plex*) dm->data;

2083:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2084:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2085:   return(0);
2086: }

2088: PetscErrorCode DMSetUp_Plex(DM dm)
2089: {
2090:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2091:   PetscInt       size;

2096:   PetscSectionSetUp(mesh->coneSection);
2097:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2098:   PetscMalloc1(size, &mesh->cones);
2099:   PetscCalloc1(size, &mesh->coneOrientations);
2100:   if (mesh->maxSupportSize) {
2101:     PetscSectionSetUp(mesh->supportSection);
2102:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2103:     PetscMalloc1(size, &mesh->supports);
2104:   }
2105:   return(0);
2106: }

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

2113:   if (subdm) {DMClone(dm, subdm);}
2114:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2115:   return(0);
2116: }

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

2121:   Not collective

2123:   Input Parameter:
2124: . mesh - The DMPlex

2126:   Output Parameter:

2128:   Note:
2129:   This should be called after all calls to DMPlexSetCone()

2131:   Level: beginner

2133: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2134: @*/
2135: PetscErrorCode DMPlexSymmetrize(DM dm)
2136: {
2137:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2138:   PetscInt      *offsets;
2139:   PetscInt       supportSize;
2140:   PetscInt       pStart, pEnd, p;

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

2151:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2152:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2153:     for (c = off; c < off+dof; ++c) {
2154:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2155:     }
2156:   }
2157:   for (p = pStart; p < pEnd; ++p) {
2158:     PetscInt dof;

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

2162:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2163:   }
2164:   PetscSectionSetUp(mesh->supportSection);
2165:   /* Calculate supports */
2166:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2167:   PetscMalloc1(supportSize, &mesh->supports);
2168:   PetscCalloc1(pEnd - pStart, &offsets);
2169:   for (p = pStart; p < pEnd; ++p) {
2170:     PetscInt dof, off, c;

2172:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2173:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2174:     for (c = off; c < off+dof; ++c) {
2175:       const PetscInt q = mesh->cones[c];
2176:       PetscInt       offS;

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

2180:       mesh->supports[offS+offsets[q]] = p;
2181:       ++offsets[q];
2182:     }
2183:   }
2184:   PetscFree(offsets);
2185:   return(0);
2186: }

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

2194:   Collective on dm

2196:   Input Parameter:
2197: . mesh - The DMPlex

2199:   Output Parameter:

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

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

2209:   Level: beginner

2211: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2212: @*/
2213: PetscErrorCode DMPlexStratify(DM dm)
2214: {
2215:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2216:   DMLabel        label;
2217:   PetscInt       pStart, pEnd, p;
2218:   PetscInt       numRoots = 0, numLeaves = 0;

2223:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2224:   /* Calculate depth */
2225:   DMPlexGetChart(dm, &pStart, &pEnd);
2226:   DMCreateLabel(dm, "depth");
2227:   DMPlexGetDepthLabel(dm, &label);
2228:   /* Initialize roots and count leaves */
2229:   for (p = pStart; p < pEnd; ++p) {
2230:     PetscInt coneSize, supportSize;

2232:     DMPlexGetConeSize(dm, p, &coneSize);
2233:     DMPlexGetSupportSize(dm, p, &supportSize);
2234:     if (!coneSize && supportSize) {
2235:       ++numRoots;
2236:       DMLabelSetValue(label, p, 0);
2237:     } else if (!supportSize && coneSize) {
2238:       ++numLeaves;
2239:     } else if (!supportSize && !coneSize) {
2240:       /* Isolated points */
2241:       DMLabelSetValue(label, p, 0);
2242:     }
2243:   }
2244:   if (numRoots + numLeaves == (pEnd - pStart)) {
2245:     for (p = pStart; p < pEnd; ++p) {
2246:       PetscInt coneSize, supportSize;

2248:       DMPlexGetConeSize(dm, p, &coneSize);
2249:       DMPlexGetSupportSize(dm, p, &supportSize);
2250:       if (!supportSize && coneSize) {
2251:         DMLabelSetValue(label, p, 1);
2252:       }
2253:     }
2254:   } else {
2255:     IS       pointIS;
2256:     PetscInt numPoints = 0, level = 0;

2258:     DMLabelGetStratumIS(label, level, &pointIS);
2259:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2260:     while (numPoints) {
2261:       const PetscInt *points;
2262:       const PetscInt  newLevel = level+1;

2264:       ISGetIndices(pointIS, &points);
2265:       for (p = 0; p < numPoints; ++p) {
2266:         const PetscInt  point = points[p];
2267:         const PetscInt *support;
2268:         PetscInt        supportSize, s;

2270:         DMPlexGetSupportSize(dm, point, &supportSize);
2271:         DMPlexGetSupport(dm, point, &support);
2272:         for (s = 0; s < supportSize; ++s) {
2273:           DMLabelSetValue(label, support[s], newLevel);
2274:         }
2275:       }
2276:       ISRestoreIndices(pointIS, &points);
2277:       ++level;
2278:       ISDestroy(&pointIS);
2279:       DMLabelGetStratumIS(label, level, &pointIS);
2280:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2281:       else         {numPoints = 0;}
2282:     }
2283:     ISDestroy(&pointIS);
2284:   }
2285:   { /* just in case there is an empty process */
2286:     PetscInt numValues, maxValues = 0, v;

2288:     DMLabelGetNumValues(label,&numValues);
2289:     for (v = 0; v < numValues; v++) {
2290:       IS pointIS;

2292:       DMLabelGetStratumIS(label, v, &pointIS);
2293:       if (pointIS) {
2294:         PetscInt  min, max, numPoints;
2295:         PetscInt  start;
2296:         PetscBool contig;

2298:         ISGetLocalSize(pointIS, &numPoints);
2299:         ISGetMinMax(pointIS, &min, &max);
2300:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2301:         if (start == 0 && contig) {
2302:           ISDestroy(&pointIS);
2303:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2304:           DMLabelSetStratumIS(label, v, pointIS);
2305:         }
2306:       }
2307:       ISDestroy(&pointIS);
2308:     }
2309:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2310:     for (v = numValues; v < maxValues; v++) {
2311:       DMLabelAddStratum(label,v);
2312:     }
2313:   }

2315:   DMLabelGetState(label, &mesh->depthState);
2316:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2317:   return(0);
2318: }

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

2323:   Not Collective

2325:   Input Parameters:
2326: + dm - The DMPlex object
2327: . numPoints - The number of input points for the join
2328: - points - The input points

2330:   Output Parameters:
2331: + numCoveredPoints - The number of points in the join
2332: - coveredPoints - The points in the join

2334:   Level: intermediate

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

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

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

2344: .keywords: mesh
2345: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2346: @*/
2347: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2348: {
2349:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2350:   PetscInt      *join[2];
2351:   PetscInt       joinSize, i = 0;
2352:   PetscInt       dof, off, p, c, m;

2360:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
2361:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
2362:   /* Copy in support of first point */
2363:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2364:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2365:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2366:     join[i][joinSize] = mesh->supports[off+joinSize];
2367:   }
2368:   /* Check each successive support */
2369:   for (p = 1; p < numPoints; ++p) {
2370:     PetscInt newJoinSize = 0;

2372:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2373:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2374:     for (c = 0; c < dof; ++c) {
2375:       const PetscInt point = mesh->supports[off+c];

2377:       for (m = 0; m < joinSize; ++m) {
2378:         if (point == join[i][m]) {
2379:           join[1-i][newJoinSize++] = point;
2380:           break;
2381:         }
2382:       }
2383:     }
2384:     joinSize = newJoinSize;
2385:     i        = 1-i;
2386:   }
2387:   *numCoveredPoints = joinSize;
2388:   *coveredPoints    = join[i];
2389:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2390:   return(0);
2391: }

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

2396:   Not Collective

2398:   Input Parameters:
2399: + dm - The DMPlex object
2400: . numPoints - The number of input points for the join
2401: - points - The input points

2403:   Output Parameters:
2404: + numCoveredPoints - The number of points in the join
2405: - coveredPoints - The points in the join

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

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

2413:   Level: intermediate

2415: .keywords: mesh
2416: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2417: @*/
2418: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2419: {

2427:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2428:   if (numCoveredPoints) *numCoveredPoints = 0;
2429:   return(0);
2430: }

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

2435:   Not Collective

2437:   Input Parameters:
2438: + dm - The DMPlex object
2439: . numPoints - The number of input points for the join
2440: - points - The input points

2442:   Output Parameters:
2443: + numCoveredPoints - The number of points in the join
2444: - coveredPoints - The points in the join

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

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

2452:   Level: intermediate

2454: .keywords: mesh
2455: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2456: @*/
2457: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2458: {
2459:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2460:   PetscInt      *offsets, **closures;
2461:   PetscInt      *join[2];
2462:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2463:   PetscInt       p, d, c, m, ms;


2472:   DMPlexGetDepth(dm, &depth);
2473:   PetscCalloc1(numPoints, &closures);
2474:   DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2475:   ms      = mesh->maxSupportSize;
2476:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2477:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
2478:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);

2480:   for (p = 0; p < numPoints; ++p) {
2481:     PetscInt closureSize;

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

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

2489:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2490:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2491:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2492:           offsets[p*(depth+2)+d+1] = i;
2493:           break;
2494:         }
2495:       }
2496:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2497:     }
2498:     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);
2499:   }
2500:   for (d = 0; d < depth+1; ++d) {
2501:     PetscInt dof;

2503:     /* Copy in support of first point */
2504:     dof = offsets[d+1] - offsets[d];
2505:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2506:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2507:     }
2508:     /* Check each successive cone */
2509:     for (p = 1; p < numPoints && joinSize; ++p) {
2510:       PetscInt newJoinSize = 0;

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

2516:         for (m = 0; m < joinSize; ++m) {
2517:           if (point == join[i][m]) {
2518:             join[1-i][newJoinSize++] = point;
2519:             break;
2520:           }
2521:         }
2522:       }
2523:       joinSize = newJoinSize;
2524:       i        = 1-i;
2525:     }
2526:     if (joinSize) break;
2527:   }
2528:   *numCoveredPoints = joinSize;
2529:   *coveredPoints    = join[i];
2530:   for (p = 0; p < numPoints; ++p) {
2531:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2532:   }
2533:   PetscFree(closures);
2534:   DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
2535:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
2536:   return(0);
2537: }

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

2542:   Not Collective

2544:   Input Parameters:
2545: + dm - The DMPlex object
2546: . numPoints - The number of input points for the meet
2547: - points - The input points

2549:   Output Parameters:
2550: + numCoveredPoints - The number of points in the meet
2551: - coveredPoints - The points in the meet

2553:   Level: intermediate

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

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

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

2563: .keywords: mesh
2564: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2565: @*/
2566: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2567: {
2568:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2569:   PetscInt      *meet[2];
2570:   PetscInt       meetSize, i = 0;
2571:   PetscInt       dof, off, p, c, m;

2579:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
2580:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
2581:   /* Copy in cone of first point */
2582:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2583:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2584:   for (meetSize = 0; meetSize < dof; ++meetSize) {
2585:     meet[i][meetSize] = mesh->cones[off+meetSize];
2586:   }
2587:   /* Check each successive cone */
2588:   for (p = 1; p < numPoints; ++p) {
2589:     PetscInt newMeetSize = 0;

2591:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2592:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2593:     for (c = 0; c < dof; ++c) {
2594:       const PetscInt point = mesh->cones[off+c];

2596:       for (m = 0; m < meetSize; ++m) {
2597:         if (point == meet[i][m]) {
2598:           meet[1-i][newMeetSize++] = point;
2599:           break;
2600:         }
2601:       }
2602:     }
2603:     meetSize = newMeetSize;
2604:     i        = 1-i;
2605:   }
2606:   *numCoveringPoints = meetSize;
2607:   *coveringPoints    = meet[i];
2608:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2609:   return(0);
2610: }

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

2615:   Not Collective

2617:   Input Parameters:
2618: + dm - The DMPlex object
2619: . numPoints - The number of input points for the meet
2620: - points - The input points

2622:   Output Parameters:
2623: + numCoveredPoints - The number of points in the meet
2624: - coveredPoints - The points in the meet

2626:   Level: intermediate

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

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

2634: .keywords: mesh
2635: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2636: @*/
2637: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2638: {

2646:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
2647:   if (numCoveredPoints) *numCoveredPoints = 0;
2648:   return(0);
2649: }

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

2654:   Not Collective

2656:   Input Parameters:
2657: + dm - The DMPlex object
2658: . numPoints - The number of input points for the meet
2659: - points - The input points

2661:   Output Parameters:
2662: + numCoveredPoints - The number of points in the meet
2663: - coveredPoints - The points in the meet

2665:   Level: intermediate

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

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

2673: .keywords: mesh
2674: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2675: @*/
2676: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2677: {
2678:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2679:   PetscInt      *offsets, **closures;
2680:   PetscInt      *meet[2];
2681:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2682:   PetscInt       p, h, c, m, mc;


2691:   DMPlexGetDepth(dm, &height);
2692:   PetscMalloc1(numPoints, &closures);
2693:   DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2694:   mc      = mesh->maxConeSize;
2695:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2696:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
2697:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);

2699:   for (p = 0; p < numPoints; ++p) {
2700:     PetscInt closureSize;

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

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

2708:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2709:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2710:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2711:           offsets[p*(height+2)+h+1] = i;
2712:           break;
2713:         }
2714:       }
2715:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2716:     }
2717:     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);
2718:   }
2719:   for (h = 0; h < height+1; ++h) {
2720:     PetscInt dof;

2722:     /* Copy in cone of first point */
2723:     dof = offsets[h+1] - offsets[h];
2724:     for (meetSize = 0; meetSize < dof; ++meetSize) {
2725:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2726:     }
2727:     /* Check each successive cone */
2728:     for (p = 1; p < numPoints && meetSize; ++p) {
2729:       PetscInt newMeetSize = 0;

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

2735:         for (m = 0; m < meetSize; ++m) {
2736:           if (point == meet[i][m]) {
2737:             meet[1-i][newMeetSize++] = point;
2738:             break;
2739:           }
2740:         }
2741:       }
2742:       meetSize = newMeetSize;
2743:       i        = 1-i;
2744:     }
2745:     if (meetSize) break;
2746:   }
2747:   *numCoveredPoints = meetSize;
2748:   *coveredPoints    = meet[i];
2749:   for (p = 0; p < numPoints; ++p) {
2750:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2751:   }
2752:   PetscFree(closures);
2753:   DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2754:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2755:   return(0);
2756: }

2758: /*@C
2759:   DMPlexEqual - Determine if two DMs have the same topology

2761:   Not Collective

2763:   Input Parameters:
2764: + dmA - A DMPlex object
2765: - dmB - A DMPlex object

2767:   Output Parameters:
2768: . equal - PETSC_TRUE if the topologies are identical

2770:   Level: intermediate

2772:   Notes:
2773:   We are not solving graph isomorphism, so we do not permutation.

2775: .keywords: mesh
2776: .seealso: DMPlexGetCone()
2777: @*/
2778: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2779: {
2780:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


2788:   *equal = PETSC_FALSE;
2789:   DMPlexGetDepth(dmA, &depth);
2790:   DMPlexGetDepth(dmB, &depthB);
2791:   if (depth != depthB) return(0);
2792:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2793:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2794:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2795:   for (p = pStart; p < pEnd; ++p) {
2796:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2797:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

2799:     DMPlexGetConeSize(dmA, p, &coneSize);
2800:     DMPlexGetCone(dmA, p, &cone);
2801:     DMPlexGetConeOrientation(dmA, p, &ornt);
2802:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2803:     DMPlexGetCone(dmB, p, &coneB);
2804:     DMPlexGetConeOrientation(dmB, p, &orntB);
2805:     if (coneSize != coneSizeB) return(0);
2806:     for (c = 0; c < coneSize; ++c) {
2807:       if (cone[c] != coneB[c]) return(0);
2808:       if (ornt[c] != orntB[c]) return(0);
2809:     }
2810:     DMPlexGetSupportSize(dmA, p, &supportSize);
2811:     DMPlexGetSupport(dmA, p, &support);
2812:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2813:     DMPlexGetSupport(dmB, p, &supportB);
2814:     if (supportSize != supportSizeB) return(0);
2815:     for (s = 0; s < supportSize; ++s) {
2816:       if (support[s] != supportB[s]) return(0);
2817:     }
2818:   }
2819:   *equal = PETSC_TRUE;
2820:   return(0);
2821: }

2823: /*@C
2824:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

2826:   Not Collective

2828:   Input Parameters:
2829: + dm         - The DMPlex
2830: . cellDim    - The cell dimension
2831: - numCorners - The number of vertices on a cell

2833:   Output Parameters:
2834: . numFaceVertices - The number of vertices on a face

2836:   Level: developer

2838:   Notes:
2839:   Of course this can only work for a restricted set of symmetric shapes

2841: .seealso: DMPlexGetCone()
2842: @*/
2843: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2844: {
2845:   MPI_Comm       comm;

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

2912: /*@
2913:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

2915:   Not Collective

2917:   Input Parameter:
2918: . dm    - The DMPlex object

2920:   Output Parameter:
2921: . depthLabel - The DMLabel recording point depth

2923:   Level: developer

2925: .keywords: mesh, points
2926: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2927: @*/
2928: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2929: {

2935:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
2936:   *depthLabel = dm->depthLabel;
2937:   return(0);
2938: }

2940: /*@
2941:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

2943:   Not Collective

2945:   Input Parameter:
2946: . dm    - The DMPlex object

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

2951:   Level: developer

2953: .keywords: mesh, points
2954: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2955: @*/
2956: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
2957: {
2958:   DMLabel        label;
2959:   PetscInt       d = 0;

2965:   DMPlexGetDepthLabel(dm, &label);
2966:   if (label) {DMLabelGetNumValues(label, &d);}
2967:   *depth = d-1;
2968:   return(0);
2969: }

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

2974:   Not Collective

2976:   Input Parameters:
2977: + dm           - The DMPlex object
2978: - stratumValue - The requested depth

2980:   Output Parameters:
2981: + start - The first point at this depth
2982: - end   - One beyond the last point at this depth

2984:   Level: developer

2986: .keywords: mesh, points
2987: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
2988: @*/
2989: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2990: {
2991:   DMLabel        label;
2992:   PetscInt       pStart, pEnd;

2999:   DMPlexGetChart(dm, &pStart, &pEnd);
3000:   if (pStart == pEnd) return(0);
3001:   if (stratumValue < 0) {
3002:     if (start) *start = pStart;
3003:     if (end)   *end   = pEnd;
3004:     return(0);
3005:   }
3006:   DMPlexGetDepthLabel(dm, &label);
3007:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3008:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3009:   return(0);
3010: }

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

3015:   Not Collective

3017:   Input Parameters:
3018: + dm           - The DMPlex object
3019: - stratumValue - The requested height

3021:   Output Parameters:
3022: + start - The first point at this height
3023: - end   - One beyond the last point at this height

3025:   Level: developer

3027: .keywords: mesh, points
3028: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3029: @*/
3030: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3031: {
3032:   DMLabel        label;
3033:   PetscInt       depth, pStart, pEnd;

3040:   DMPlexGetChart(dm, &pStart, &pEnd);
3041:   if (pStart == pEnd) return(0);
3042:   if (stratumValue < 0) {
3043:     if (start) *start = pStart;
3044:     if (end)   *end   = pEnd;
3045:     return(0);
3046:   }
3047:   DMPlexGetDepthLabel(dm, &label);
3048:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3049:   DMLabelGetNumValues(label, &depth);
3050:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3051:   return(0);
3052: }

3054: /* Set the number of dof on each point and separate by fields */
3055: static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3056: {
3057:   PetscInt      *pMax;
3058:   PetscInt       depth, pStart = 0, pEnd = 0;
3059:   PetscInt       Nf, p, d, dep, f;
3060:   PetscBool     *isFE;

3064:   PetscMalloc1(numFields, &isFE);
3065:   DMGetNumFields(dm, &Nf);
3066:   for (f = 0; f < numFields; ++f) {
3067:     PetscObject  obj;
3068:     PetscClassId id;

3070:     isFE[f] = PETSC_FALSE;
3071:     if (f >= Nf) continue;
3072:     DMGetField(dm, f, &obj);
3073:     PetscObjectGetClassId(obj, &id);
3074:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
3075:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3076:   }
3077:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
3078:   if (numFields > 0) {
3079:     PetscSectionSetNumFields(*section, numFields);
3080:     if (numComp) {
3081:       for (f = 0; f < numFields; ++f) {
3082:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
3083:         if (isFE[f]) {
3084:           PetscFE           fe;
3085:           PetscDualSpace    dspace;
3086:           const PetscInt    ***perms;
3087:           const PetscScalar ***flips;
3088:           const PetscInt    *numDof;

3090:           DMGetField(dm,f,(PetscObject *) &fe);
3091:           PetscFEGetDualSpace(fe,&dspace);
3092:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3093:           PetscDualSpaceGetNumDof(dspace,&numDof);
3094:           if (perms || flips) {
3095:             DM               K;
3096:             DMLabel          depthLabel;
3097:             PetscInt         depth, h;
3098:             PetscSectionSym  sym;

3100:             PetscDualSpaceGetDM(dspace,&K);
3101:             DMPlexGetDepthLabel(dm,&depthLabel);
3102:             DMPlexGetDepth(dm,&depth);
3103:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
3104:             for (h = 0; h <= depth; h++) {
3105:               PetscDualSpace    hspace;
3106:               PetscInt          kStart, kEnd;
3107:               PetscInt          kConeSize;
3108:               const PetscInt    **perms0 = NULL;
3109:               const PetscScalar **flips0 = NULL;

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

3140:       for (f = 0; f < numFields; ++f) {
3141:         if (isFE[f] && p >= pMax[dep]) continue;
3142:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3143:         tot += numDof[f*(dim+1)+d];
3144:       }
3145:       PetscSectionSetDof(*section, p, tot);
3146:     }
3147:   }
3148:   PetscFree(pMax);
3149:   PetscFree(isFE);
3150:   return(0);
3151: }

3153: /* Set the number of dof on each point and separate by fields
3154:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3155: */
3156: static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3157: {
3158:   PetscInt       numFields;
3159:   PetscInt       bc;
3160:   PetscSection   aSec;

3164:   PetscSectionGetNumFields(section, &numFields);
3165:   for (bc = 0; bc < numBC; ++bc) {
3166:     PetscInt        field = 0;
3167:     const PetscInt *comp;
3168:     const PetscInt *idx;
3169:     PetscInt        Nc = -1, n, i;

3171:     if (numFields) field = bcField[bc];
3172:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3173:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3174:     ISGetLocalSize(bcPoints[bc], &n);
3175:     ISGetIndices(bcPoints[bc], &idx);
3176:     for (i = 0; i < n; ++i) {
3177:       const PetscInt p = idx[i];
3178:       PetscInt       numConst;

3180:       if (numFields) {
3181:         PetscSectionGetFieldDof(section, p, field, &numConst);
3182:       } else {
3183:         PetscSectionGetDof(section, p, &numConst);
3184:       }
3185:       /* If Nc < 0, constrain every dof on the point */
3186:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3187:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3188:       PetscSectionAddConstraintDof(section, p, numConst);
3189:     }
3190:     ISRestoreIndices(bcPoints[bc], &idx);
3191:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3192:   }
3193:   DMPlexGetAnchors(dm, &aSec, NULL);
3194:   if (aSec) {
3195:     PetscInt aStart, aEnd, a;

3197:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3198:     for (a = aStart; a < aEnd; a++) {
3199:       PetscInt dof, f;

3201:       PetscSectionGetDof(aSec, a, &dof);
3202:       if (dof) {
3203:         /* if there are point-to-point constraints, then all dofs are constrained */
3204:         PetscSectionGetDof(section, a, &dof);
3205:         PetscSectionSetConstraintDof(section, a, dof);
3206:         for (f = 0; f < numFields; f++) {
3207:           PetscSectionGetFieldDof(section, a, f, &dof);
3208:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3209:         }
3210:       }
3211:     }
3212:   }
3213:   return(0);
3214: }

3216: /* Set the constrained field indices on each point
3217:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3218: */
3219: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3220: {
3221:   PetscSection   aSec;
3222:   PetscInt      *indices;
3223:   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;

3227:   PetscSectionGetNumFields(section, &numFields);
3228:   if (!numFields) return(0);
3229:   /* Initialize all field indices to -1 */
3230:   PetscSectionGetChart(section, &pStart, &pEnd);
3231:   PetscSectionGetMaxDof(section, &maxDof);
3232:   PetscMalloc1(maxDof, &indices);
3233:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3234:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3235:   /* Handle BC constraints */
3236:   for (bc = 0; bc < numBC; ++bc) {
3237:     const PetscInt  field = bcField[bc];
3238:     const PetscInt *comp, *idx;
3239:     PetscInt        Nc = -1, n, i;

3241:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3242:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3243:     ISGetLocalSize(bcPoints[bc], &n);
3244:     ISGetIndices(bcPoints[bc], &idx);
3245:     for (i = 0; i < n; ++i) {
3246:       const PetscInt  p = idx[i];
3247:       const PetscInt *find;
3248:       PetscInt        fcdof, c;

3250:       PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3251:       if (Nc < 0) {
3252:         for (d = 0; d < fcdof; ++d) indices[d] = d;
3253:       } else {
3254:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3255:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3256:         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
3257:         PetscSortInt(d+Nc, indices);
3258:         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
3259:       }
3260:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3261:     }
3262:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3263:     ISRestoreIndices(bcPoints[bc], &idx);
3264:   }
3265:   /* Handle anchors */
3266:   DMPlexGetAnchors(dm, &aSec, NULL);
3267:   if (aSec) {
3268:     PetscInt aStart, aEnd, a;

3270:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3271:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3272:     for (a = aStart; a < aEnd; a++) {
3273:       PetscInt dof, fdof, f;

3275:       PetscSectionGetDof(aSec, a, &dof);
3276:       if (dof) {
3277:         /* if there are point-to-point constraints, then all dofs are constrained */
3278:         for (f = 0; f < numFields; f++) {
3279:           PetscSectionGetFieldDof(section, a, f, &fdof);
3280:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3281:         }
3282:       }
3283:     }
3284:   }
3285:   PetscFree(indices);
3286:   return(0);
3287: }

3289: /* Set the constrained indices on each point */
3290: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3291: {
3292:   PetscInt      *indices;
3293:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3297:   PetscSectionGetNumFields(section, &numFields);
3298:   PetscSectionGetMaxDof(section, &maxDof);
3299:   PetscSectionGetChart(section, &pStart, &pEnd);
3300:   PetscMalloc1(maxDof, &indices);
3301:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3302:   for (p = pStart; p < pEnd; ++p) {
3303:     PetscInt cdof, d;

3305:     PetscSectionGetConstraintDof(section, p, &cdof);
3306:     if (cdof) {
3307:       if (numFields) {
3308:         PetscInt numConst = 0, foff = 0;

3310:         for (f = 0; f < numFields; ++f) {
3311:           const PetscInt *find;
3312:           PetscInt        fcdof, fdof;

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

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

3336:   Not Collective

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

3350:   Output Parameter:
3351: . section - The PetscSection object

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

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

3358:   Level: developer

3360:   Fortran Notes:
3361:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3363: .keywords: mesh, elements
3364: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3365: @*/
3366: 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)
3367: {
3368:   PetscSection   aSec;

3372:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3373:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3374:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3375:   PetscSectionSetUp(*section);
3376:   DMPlexGetAnchors(dm,&aSec,NULL);
3377:   if (numBC || aSec) {
3378:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3379:     DMPlexCreateSectionBCIndices(dm, *section);
3380:   }
3381:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3382:   return(0);
3383: }

3385: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3386: {
3387:   PetscSection   section, s;
3388:   Mat            m;
3389:   PetscInt       maxHeight;

3393:   DMClone(dm, cdm);
3394:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3395:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3396:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3397:   DMSetDefaultSection(*cdm, section);
3398:   PetscSectionDestroy(&section);
3399:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3400:   MatCreate(PETSC_COMM_SELF, &m);
3401:   DMSetDefaultConstraints(*cdm, s, m);
3402:   PetscSectionDestroy(&s);
3403:   MatDestroy(&m);
3404:   return(0);
3405: }

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

3410:   Not Collective

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

3415:   Output Parameter:
3416: . section - The PetscSection object

3418:   Level: developer

3420: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3421: @*/
3422: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3423: {
3424:   DM_Plex *mesh = (DM_Plex*) dm->data;

3428:   if (section) *section = mesh->coneSection;
3429:   return(0);
3430: }

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

3435:   Not Collective

3437:   Input Parameters:
3438: . dm        - The DMPlex object

3440:   Output Parameter:
3441: . section - The PetscSection object

3443:   Level: developer

3445: .seealso: DMPlexGetConeSection()
3446: @*/
3447: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3448: {
3449:   DM_Plex *mesh = (DM_Plex*) dm->data;

3453:   if (section) *section = mesh->supportSection;
3454:   return(0);
3455: }

3457: /*@C
3458:   DMPlexGetCones - Return cone data

3460:   Not Collective

3462:   Input Parameters:
3463: . dm        - The DMPlex object

3465:   Output Parameter:
3466: . cones - The cone for each point

3468:   Level: developer

3470: .seealso: DMPlexGetConeSection()
3471: @*/
3472: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3473: {
3474:   DM_Plex *mesh = (DM_Plex*) dm->data;

3478:   if (cones) *cones = mesh->cones;
3479:   return(0);
3480: }

3482: /*@C
3483:   DMPlexGetConeOrientations - Return cone orientation data

3485:   Not Collective

3487:   Input Parameters:
3488: . dm        - The DMPlex object

3490:   Output Parameter:
3491: . coneOrientations - The cone orientation for each point

3493:   Level: developer

3495: .seealso: DMPlexGetConeSection()
3496: @*/
3497: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3498: {
3499:   DM_Plex *mesh = (DM_Plex*) dm->data;

3503:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3504:   return(0);
3505: }

3507: /******************************** FEM Support **********************************/

3509: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section)
3510: {
3511:   PetscInt      *perm;
3512:   PetscInt       dim, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

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

3539:          v_lb, {e_b}, v_rb,
3540:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3541:          v_lt, reverse {e_t}, v_rt
3542:       */
3543:       {
3544:         const PetscInt of   = 0;
3545:         const PetscInt oeb  = of   + PetscSqr(k-1);
3546:         const PetscInt oer  = oeb  + (k-1);
3547:         const PetscInt oet  = oer  + (k-1);
3548:         const PetscInt oel  = oet  + (k-1);
3549:         const PetscInt ovlb = oel  + (k-1);
3550:         const PetscInt ovrb = ovlb + 1;
3551:         const PetscInt ovrt = ovrb + 1;
3552:         const PetscInt ovlt = ovrt + 1;
3553:         PetscInt       o;

3555:         /* bottom */
3556:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3557:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3558:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3559:         /* middle */
3560:         for (i = 0; i < k-1; ++i) {
3561:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3562:           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;
3563:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3564:         }
3565:         /* top */
3566:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3567:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3568:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3569:         foffset = offset;
3570:       }
3571:       break;
3572:     case 3:
3573:       /* The original hex closure is

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

3590:          Middle Slice (j)
3591:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3592:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3593:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

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

3630:         /* Bottom Slice */
3631:         /*   bottom */
3632:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3633:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3634:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3635:         /*   middle */
3636:         for (i = 0; i < k-1; ++i) {
3637:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3638:           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;}
3639:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3640:         }
3641:         /*   top */
3642:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3643:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3644:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3646:         /* Middle Slice */
3647:         for (j = 0; j < k-1; ++j) {
3648:           /*   bottom */
3649:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3650:           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;
3651:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3652:           /*   middle */
3653:           for (i = 0; i < k-1; ++i) {
3654:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3655:             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;
3656:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3657:           }
3658:           /*   top */
3659:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3660:           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;
3661:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3662:         }

3664:         /* Top Slice */
3665:         /*   bottom */
3666:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3667:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3668:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3669:         /*   middle */
3670:         for (i = 0; i < k-1; ++i) {
3671:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3672:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3673:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3674:         }
3675:         /*   top */
3676:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3677:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3678:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3680:         foffset = offset;
3681:       }
3682:       break;
3683:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3684:     }
3685:   }
3686:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3687:   /* Check permutation */
3688:   {
3689:     PetscInt *check;

3691:     PetscMalloc1(size, &check);
3692:     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]);}
3693:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3694:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3695:     PetscFree(check);
3696:   }
3697:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3698:   return(0);
3699: }

3701: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3702: {
3703:   PetscDS        prob;
3704:   PetscInt       depth, Nf, h;
3705:   DMLabel        label;

3709:   prob    = dm->prob;
3710:   Nf      = prob->Nf;
3711:   label   = dm->depthLabel;
3712:   *dspace = NULL;
3713:   if (field < Nf) {
3714:     PetscObject disc = prob->disc[field];

3716:     if (disc->classid == PETSCFE_CLASSID) {
3717:       PetscDualSpace dsp;

3719:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3720:       DMLabelGetNumValues(label,&depth);
3721:       DMLabelGetValue(label,point,&h);
3722:       h    = depth - 1 - h;
3723:       if (h) {
3724:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3725:       } else {
3726:         *dspace = dsp;
3727:       }
3728:     }
3729:   }
3730:   return(0);
3731: }


3734: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3735: {
3736:   PetscScalar    *array, *vArray;
3737:   const PetscInt *cone, *coneO;
3738:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3739:   PetscErrorCode  ierr;

3742:   PetscSectionGetChart(section, &pStart, &pEnd);
3743:   DMPlexGetConeSize(dm, point, &numPoints);
3744:   DMPlexGetCone(dm, point, &cone);
3745:   DMPlexGetConeOrientation(dm, point, &coneO);
3746:   if (!values || !*values) {
3747:     if ((point >= pStart) && (point < pEnd)) {
3748:       PetscInt dof;

3750:       PetscSectionGetDof(section, point, &dof);
3751:       size += dof;
3752:     }
3753:     for (p = 0; p < numPoints; ++p) {
3754:       const PetscInt cp = cone[p];
3755:       PetscInt       dof;

3757:       if ((cp < pStart) || (cp >= pEnd)) continue;
3758:       PetscSectionGetDof(section, cp, &dof);
3759:       size += dof;
3760:     }
3761:     if (!values) {
3762:       if (csize) *csize = size;
3763:       return(0);
3764:     }
3765:     DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
3766:   } else {
3767:     array = *values;
3768:   }
3769:   size = 0;
3770:   VecGetArray(v, &vArray);
3771:   if ((point >= pStart) && (point < pEnd)) {
3772:     PetscInt     dof, off, d;
3773:     PetscScalar *varr;

3775:     PetscSectionGetDof(section, point, &dof);
3776:     PetscSectionGetOffset(section, point, &off);
3777:     varr = &vArray[off];
3778:     for (d = 0; d < dof; ++d, ++offset) {
3779:       array[offset] = varr[d];
3780:     }
3781:     size += dof;
3782:   }
3783:   for (p = 0; p < numPoints; ++p) {
3784:     const PetscInt cp = cone[p];
3785:     PetscInt       o  = coneO[p];
3786:     PetscInt       dof, off, d;
3787:     PetscScalar   *varr;

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

3815: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3816: {
3817:   const PetscInt *cla;
3818:   PetscInt       np, *pts = NULL;

3822:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3823:   if (!*clPoints) {
3824:     PetscInt pStart, pEnd, p, q;

3826:     PetscSectionGetChart(section, &pStart, &pEnd);
3827:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3828:     /* Compress out points not in the section */
3829:     for (p = 0, q = 0; p < np; p++) {
3830:       PetscInt r = pts[2*p];
3831:       if ((r >= pStart) && (r < pEnd)) {
3832:         pts[q*2]   = r;
3833:         pts[q*2+1] = pts[2*p+1];
3834:         ++q;
3835:       }
3836:     }
3837:     np = q;
3838:     cla = NULL;
3839:   } else {
3840:     PetscInt dof, off;

3842:     PetscSectionGetDof(*clSec, point, &dof);
3843:     PetscSectionGetOffset(*clSec, point, &off);
3844:     ISGetIndices(*clPoints, &cla);
3845:     np   = dof/2;
3846:     pts  = (PetscInt *) &cla[off];
3847:   }
3848:   *numPoints = np;
3849:   *points    = pts;
3850:   *clp       = cla;

3852:   return(0);
3853: }

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

3860:   if (!*clPoints) {
3861:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3862:   } else {
3863:     ISRestoreIndices(*clPoints, clp);
3864:   }
3865:   *numPoints = 0;
3866:   *points    = NULL;
3867:   *clSec     = NULL;
3868:   *clPoints  = NULL;
3869:   *clp       = NULL;
3870:   return(0);
3871: }

3873: 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[])
3874: {
3875:   PetscInt          offset = 0, p;
3876:   const PetscInt    **perms = NULL;
3877:   const PetscScalar **flips = NULL;
3878:   PetscErrorCode    ierr;

3881:   *size = 0;
3882:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3883:   for (p = 0; p < numPoints; p++) {
3884:     const PetscInt    point = points[2*p];
3885:     const PetscInt    *perm = perms ? perms[p] : NULL;
3886:     const PetscScalar *flip = flips ? flips[p] : NULL;
3887:     PetscInt          dof, off, d;
3888:     const PetscScalar *varr;

3890:     PetscSectionGetDof(section, point, &dof);
3891:     PetscSectionGetOffset(section, point, &off);
3892:     varr = &vArray[off];
3893:     if (clperm) {
3894:       if (perm) {
3895:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3896:       } else {
3897:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
3898:       }
3899:       if (flip) {
3900:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
3901:       }
3902:     } else {
3903:       if (perm) {
3904:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
3905:       } else {
3906:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
3907:       }
3908:       if (flip) {
3909:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
3910:       }
3911:     }
3912:     offset += dof;
3913:   }
3914:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3915:   *size = offset;
3916:   return(0);
3917: }

3919: 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[])
3920: {
3921:   PetscInt          offset = 0, f;
3922:   PetscErrorCode    ierr;

3925:   *size = 0;
3926:   for (f = 0; f < numFields; ++f) {
3927:     PetscInt          p;
3928:     const PetscInt    **perms = NULL;
3929:     const PetscScalar **flips = NULL;

3931:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3932:     for (p = 0; p < numPoints; p++) {
3933:       const PetscInt    point = points[2*p];
3934:       PetscInt          fdof, foff, b;
3935:       const PetscScalar *varr;
3936:       const PetscInt    *perm = perms ? perms[p] : NULL;
3937:       const PetscScalar *flip = flips ? flips[p] : NULL;

3939:       PetscSectionGetFieldDof(section, point, f, &fdof);
3940:       PetscSectionGetFieldOffset(section, point, f, &foff);
3941:       varr = &vArray[foff];
3942:       if (clperm) {
3943:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
3944:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
3945:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
3946:       } else {
3947:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
3948:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
3949:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
3950:       }
3951:       offset += fdof;
3952:     }
3953:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3954:   }
3955:   *size = offset;
3956:   return(0);
3957: }

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

3962:   Not collective

3964:   Input Parameters:
3965: + dm - The DM
3966: . section - The section describing the layout in v, or NULL to use the default section
3967: . v - The local vector
3968: - point - The sieve point in the DM

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

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

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

3980:   Level: intermediate

3982: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3983: @*/
3984: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3985: {
3986:   PetscSection       clSection;
3987:   IS                 clPoints;
3988:   PetscScalar       *array;
3989:   const PetscScalar *vArray;
3990:   PetscInt          *points = NULL;
3991:   const PetscInt    *clp, *perm;
3992:   PetscInt           depth, numFields, numPoints, size;
3993:   PetscErrorCode     ierr;

3997:   if (!section) {DMGetDefaultSection(dm, &section);}
4000:   DMPlexGetDepth(dm, &depth);
4001:   PetscSectionGetNumFields(section, &numFields);
4002:   if (depth == 1 && numFields < 2) {
4003:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4004:     return(0);
4005:   }
4006:   /* Get points */
4007:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4008:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4009:   /* Get array */
4010:   if (!values || !*values) {
4011:     PetscInt asize = 0, dof, p;

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

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

4047:   Not collective

4049:   Input Parameters:
4050: + dm - The DM
4051: . section - The section describing the layout in v, or NULL to use the default section
4052: . v - The local vector
4053: . point - The sieve point in the DM
4054: . csize - The number of values in the closure, or NULL
4055: - values - The array of values, which is a borrowed array and should not be freed

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

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

4063:   Level: intermediate

4065: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4066: @*/
4067: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4068: {
4069:   PetscInt       size = 0;

4073:   /* Should work without recalculating size */
4074:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
4075:   return(0);
4076: }

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

4081: 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[])
4082: {
4083:   PetscInt        cdof;   /* The number of constraints on this point */
4084:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4085:   PetscScalar    *a;
4086:   PetscInt        off, cind = 0, k;
4087:   PetscErrorCode  ierr;

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

4131: 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[])
4132: {
4133:   PetscInt        cdof;   /* The number of constraints on this point */
4134:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4135:   PetscScalar    *a;
4136:   PetscInt        off, cind = 0, k;
4137:   PetscErrorCode  ierr;

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

4182: 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[])
4183: {
4184:   PetscScalar    *a;
4185:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4186:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4187:   PetscInt        cind = 0, b;
4188:   PetscErrorCode  ierr;

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

4235: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4236: {
4237:   PetscScalar    *a;
4238:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4239:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4240:   PetscInt        cind = 0, b;
4241:   PetscErrorCode  ierr;

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

4288: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4289: {
4290:   PetscScalar    *array;
4291:   const PetscInt *cone, *coneO;
4292:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4293:   PetscErrorCode  ierr;

4296:   PetscSectionGetChart(section, &pStart, &pEnd);
4297:   DMPlexGetConeSize(dm, point, &numPoints);
4298:   DMPlexGetCone(dm, point, &cone);
4299:   DMPlexGetConeOrientation(dm, point, &coneO);
4300:   VecGetArray(v, &array);
4301:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4302:     const PetscInt cp = !p ? point : cone[p-1];
4303:     const PetscInt o  = !p ? 0     : coneO[p-1];

4305:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4306:     PetscSectionGetDof(section, cp, &dof);
4307:     /* ADD_VALUES */
4308:     {
4309:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4310:       PetscScalar    *a;
4311:       PetscInt        cdof, coff, cind = 0, k;

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

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

4349:   Not collective

4351:   Input Parameters:
4352: + dm - The DM
4353: . section - The section describing the layout in v, or NULL to use the default section
4354: . v - The local vector
4355: . point - The sieve point in the DM
4356: . values - The array of values
4357: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

4362:   Level: intermediate

4364: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4365: @*/
4366: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4367: {
4368:   PetscSection    clSection;
4369:   IS              clPoints;
4370:   PetscScalar    *array;
4371:   PetscInt       *points = NULL;
4372:   const PetscInt *clp, *clperm;
4373:   PetscInt        depth, numFields, numPoints, p;
4374:   PetscErrorCode  ierr;

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

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

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

4515: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
4516: {
4517:   PetscSection      clSection;
4518:   IS                clPoints;
4519:   PetscScalar       *array;
4520:   PetscInt          *points = NULL;
4521:   const PetscInt    *clp, *clperm;
4522:   PetscInt          numFields, numPoints, p;
4523:   PetscInt          offset = 0, f;
4524:   PetscErrorCode    ierr;

4528:   if (!section) {DMGetDefaultSection(dm, &section);}
4531:   PetscSectionGetNumFields(section, &numFields);
4532:   /* Get points */
4533:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4534:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4535:   /* Get array */
4536:   VecGetArray(v, &array);
4537:   /* Get values */
4538:   for (f = 0; f < numFields; ++f) {
4539:     const PetscInt    **perms = NULL;
4540:     const PetscScalar **flips = NULL;

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

4599: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4600: {
4601:   PetscMPIInt    rank;
4602:   PetscInt       i, j;

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

4625: /* . off - The global offset of this point */
4626: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4627: {
4628:   PetscInt        dof;    /* The number of unknowns on this point */
4629:   PetscInt        cdof;   /* The number of constraints on this point */
4630:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4631:   PetscInt        cind = 0, k;
4632:   PetscErrorCode  ierr;

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

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

4678:   PetscSectionGetNumFields(section, &numFields);
4679:   for (f = 0, foff = 0; f < numFields; ++f) {
4680:     PetscInt        fdof, cfdof;
4681:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4682:     PetscInt        cind = 0, b;
4683:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

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

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

4740:   PetscSectionGetNumFields(section, &numFields);

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

4755:       PetscSectionGetDof(section,b,&bSecDof);
4756:       if (!bSecDof) {
4757:         continue;
4758:       }
4759:       if (b >= aStart && b < aEnd) {
4760:         PetscSectionGetDof(aSec,b,&bDof);
4761:       }
4762:       if (bDof) {
4763:         /* this point is constrained */
4764:         /* it is going to be replaced by its anchors */
4765:         PetscInt bOff, q;

4767:         anyConstrained = PETSC_TRUE;
4768:         newNumPoints  += bDof;
4769:         PetscSectionGetOffset(aSec,b,&bOff);
4770:         for (q = 0; q < bDof; q++) {
4771:           PetscInt a = anchors[bOff + q];
4772:           PetscInt aDof;

4774:           PetscSectionGetDof(section,a,&aDof);
4775:           newNumIndices += aDof;
4776:           for (f = 0; f < numFields; ++f) {
4777:             PetscInt fDof;

4779:             PetscSectionGetFieldDof(section, a, f, &fDof);
4780:             newOffsets[f+1] += fDof;
4781:           }
4782:         }
4783:       }
4784:       else {
4785:         /* this point is not constrained */
4786:         newNumPoints++;
4787:         newNumIndices += bSecDof;
4788:         for (f = 0; f < numFields; ++f) {
4789:           PetscInt fDof;

4791:           PetscSectionGetFieldDof(section, b, f, &fDof);
4792:           newOffsets[f+1] += fDof;
4793:         }
4794:       }
4795:     }
4796:   }
4797:   if (!anyConstrained) {
4798:     if (outNumPoints)  *outNumPoints  = 0;
4799:     if (outNumIndices) *outNumIndices = 0;
4800:     if (outPoints)     *outPoints     = NULL;
4801:     if (outValues)     *outValues     = NULL;
4802:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4803:     return(0);
4804:   }

4806:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4807:   if (outNumIndices) *outNumIndices = newNumIndices;

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

4811:   if (!outPoints && !outValues) {
4812:     if (offsets) {
4813:       for (f = 0; f <= numFields; f++) {
4814:         offsets[f] = newOffsets[f];
4815:       }
4816:     }
4817:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4818:     return(0);
4819:   }

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

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

4825:   /* workspaces */
4826:   if (numFields) {
4827:     for (f = 0; f < numFields; f++) {
4828:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
4829:       DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
4830:     }
4831:   }
4832:   else {
4833:     DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
4834:     DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);
4835:   }

4837:   /* get workspaces for the point-to-point matrices */
4838:   if (numFields) {
4839:     PetscInt totalOffset, totalMatOffset;

4841:     for (p = 0; p < numPoints; p++) {
4842:       PetscInt b    = points[2*p];
4843:       PetscInt bDof = 0, bSecDof;

4845:       PetscSectionGetDof(section,b,&bSecDof);
4846:       if (!bSecDof) {
4847:         for (f = 0; f < numFields; f++) {
4848:           newPointOffsets[f][p + 1] = 0;
4849:           pointMatOffsets[f][p + 1] = 0;
4850:         }
4851:         continue;
4852:       }
4853:       if (b >= aStart && b < aEnd) {
4854:         PetscSectionGetDof(aSec, b, &bDof);
4855:       }
4856:       if (bDof) {
4857:         for (f = 0; f < numFields; f++) {
4858:           PetscInt fDof, q, bOff, allFDof = 0;

4860:           PetscSectionGetFieldDof(section, b, f, &fDof);
4861:           PetscSectionGetOffset(aSec, b, &bOff);
4862:           for (q = 0; q < bDof; q++) {
4863:             PetscInt a = anchors[bOff + q];
4864:             PetscInt aFDof;

4866:             PetscSectionGetFieldDof(section, a, f, &aFDof);
4867:             allFDof += aFDof;
4868:           }
4869:           newPointOffsets[f][p+1] = allFDof;
4870:           pointMatOffsets[f][p+1] = fDof * allFDof;
4871:         }
4872:       }
4873:       else {
4874:         for (f = 0; f < numFields; f++) {
4875:           PetscInt fDof;

4877:           PetscSectionGetFieldDof(section, b, f, &fDof);
4878:           newPointOffsets[f][p+1] = fDof;
4879:           pointMatOffsets[f][p+1] = 0;
4880:         }
4881:       }
4882:     }
4883:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
4884:       newPointOffsets[f][0] = totalOffset;
4885:       pointMatOffsets[f][0] = totalMatOffset;
4886:       for (p = 0; p < numPoints; p++) {
4887:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4888:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4889:       }
4890:       totalOffset    = newPointOffsets[f][numPoints];
4891:       totalMatOffset = pointMatOffsets[f][numPoints];
4892:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
4893:     }
4894:   }
4895:   else {
4896:     for (p = 0; p < numPoints; p++) {
4897:       PetscInt b    = points[2*p];
4898:       PetscInt bDof = 0, bSecDof;

4900:       PetscSectionGetDof(section,b,&bSecDof);
4901:       if (!bSecDof) {
4902:         newPointOffsets[0][p + 1] = 0;
4903:         pointMatOffsets[0][p + 1] = 0;
4904:         continue;
4905:       }
4906:       if (b >= aStart && b < aEnd) {
4907:         PetscSectionGetDof(aSec, b, &bDof);
4908:       }
4909:       if (bDof) {
4910:         PetscInt bOff, q, allDof = 0;

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

4916:           PetscSectionGetDof(section, a, &aDof);
4917:           allDof += aDof;
4918:         }
4919:         newPointOffsets[0][p+1] = allDof;
4920:         pointMatOffsets[0][p+1] = bSecDof * allDof;
4921:       }
4922:       else {
4923:         newPointOffsets[0][p+1] = bSecDof;
4924:         pointMatOffsets[0][p+1] = 0;
4925:       }
4926:     }
4927:     newPointOffsets[0][0] = 0;
4928:     pointMatOffsets[0][0] = 0;
4929:     for (p = 0; p < numPoints; p++) {
4930:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4931:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4932:     }
4933:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
4934:   }

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

4939:   /* get the point-to-point matrices; construct newPoints */
4940:   PetscSectionGetMaxDof(aSec, &maxAnchor);
4941:   PetscSectionGetMaxDof(section, &maxDof);
4942:   DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);
4943:   DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);
4944:   if (numFields) {
4945:     for (p = 0, newP = 0; p < numPoints; p++) {
4946:       PetscInt b    = points[2*p];
4947:       PetscInt o    = points[2*p+1];
4948:       PetscInt bDof = 0, bSecDof;

4950:       PetscSectionGetDof(section, b, &bSecDof);
4951:       if (!bSecDof) {
4952:         continue;
4953:       }
4954:       if (b >= aStart && b < aEnd) {
4955:         PetscSectionGetDof(aSec, b, &bDof);
4956:       }
4957:       if (bDof) {
4958:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

4960:         fStart[0] = 0;
4961:         fEnd[0]   = 0;
4962:         for (f = 0; f < numFields; f++) {
4963:           PetscInt fDof;

4965:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
4966:           fStart[f+1] = fStart[f] + fDof;
4967:           fEnd[f+1]   = fStart[f+1];
4968:         }
4969:         PetscSectionGetOffset(cSec, b, &bOff);
4970:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

4972:         fAnchorStart[0] = 0;
4973:         fAnchorEnd[0]   = 0;
4974:         for (f = 0; f < numFields; f++) {
4975:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

4977:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4978:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4979:         }
4980:         PetscSectionGetOffset(aSec, b, &bOff);
4981:         for (q = 0; q < bDof; q++) {
4982:           PetscInt a = anchors[bOff + q], aOff;

4984:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4985:           newPoints[2*(newP + q)]     = a;
4986:           newPoints[2*(newP + q) + 1] = 0;
4987:           PetscSectionGetOffset(section, a, &aOff);
4988:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
4989:         }
4990:         newP += bDof;

4992:         if (outValues) {
4993:           /* get the point-to-point submatrix */
4994:           for (f = 0; f < numFields; f++) {
4995:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
4996:           }
4997:         }
4998:       }
4999:       else {
5000:         newPoints[2 * newP]     = b;
5001:         newPoints[2 * newP + 1] = o;
5002:         newP++;
5003:       }
5004:     }
5005:   } else {
5006:     for (p = 0; p < numPoints; p++) {
5007:       PetscInt b    = points[2*p];
5008:       PetscInt o    = points[2*p+1];
5009:       PetscInt bDof = 0, bSecDof;

5011:       PetscSectionGetDof(section, b, &bSecDof);
5012:       if (!bSecDof) {
5013:         continue;
5014:       }
5015:       if (b >= aStart && b < aEnd) {
5016:         PetscSectionGetDof(aSec, b, &bDof);
5017:       }
5018:       if (bDof) {
5019:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5030:           newPoints[2*(newP + q)]     = a;
5031:           newPoints[2*(newP + q) + 1] = 0;
5032:           PetscSectionGetOffset(section, a, &aOff);
5033:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5034:         }
5035:         newP += bDof;

5037:         /* get the point-to-point submatrix */
5038:         if (outValues) {
5039:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5040:         }
5041:       }
5042:       else {
5043:         newPoints[2 * newP]     = b;
5044:         newPoints[2 * newP + 1] = o;
5045:         newP++;
5046:       }
5047:     }
5048:   }

5050:   if (outValues) {
5051:     DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5052:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5053:     /* multiply constraints on the right */
5054:     if (numFields) {
5055:       for (f = 0; f < numFields; f++) {
5056:         PetscInt oldOff = offsets[f];

5058:         for (p = 0; p < numPoints; p++) {
5059:           PetscInt cStart = newPointOffsets[f][p];
5060:           PetscInt b      = points[2 * p];
5061:           PetscInt c, r, k;
5062:           PetscInt dof;

5064:           PetscSectionGetFieldDof(section,b,f,&dof);
5065:           if (!dof) {
5066:             continue;
5067:           }
5068:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5069:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5070:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5072:             for (r = 0; r < numIndices; r++) {
5073:               for (c = 0; c < nCols; c++) {
5074:                 for (k = 0; k < dof; k++) {
5075:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5076:                 }
5077:               }
5078:             }
5079:           }
5080:           else {
5081:             /* copy this column as is */
5082:             for (r = 0; r < numIndices; r++) {
5083:               for (c = 0; c < dof; c++) {
5084:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5085:               }
5086:             }
5087:           }
5088:           oldOff += dof;
5089:         }
5090:       }
5091:     }
5092:     else {
5093:       PetscInt oldOff = 0;
5094:       for (p = 0; p < numPoints; p++) {
5095:         PetscInt cStart = newPointOffsets[0][p];
5096:         PetscInt b      = points[2 * p];
5097:         PetscInt c, r, k;
5098:         PetscInt dof;

5100:         PetscSectionGetDof(section,b,&dof);
5101:         if (!dof) {
5102:           continue;
5103:         }
5104:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5105:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5106:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5108:           for (r = 0; r < numIndices; r++) {
5109:             for (c = 0; c < nCols; c++) {
5110:               for (k = 0; k < dof; k++) {
5111:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5112:               }
5113:             }
5114:           }
5115:         }
5116:         else {
5117:           /* copy this column as is */
5118:           for (r = 0; r < numIndices; r++) {
5119:             for (c = 0; c < dof; c++) {
5120:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5121:             }
5122:           }
5123:         }
5124:         oldOff += dof;
5125:       }
5126:     }

5128:     if (multiplyLeft) {
5129:       DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);
5130:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5131:       /* multiply constraints transpose on the left */
5132:       if (numFields) {
5133:         for (f = 0; f < numFields; f++) {
5134:           PetscInt oldOff = offsets[f];

5136:           for (p = 0; p < numPoints; p++) {
5137:             PetscInt rStart = newPointOffsets[f][p];
5138:             PetscInt b      = points[2 * p];
5139:             PetscInt c, r, k;
5140:             PetscInt dof;

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

5147:               for (r = 0; r < nRows; r++) {
5148:                 for (c = 0; c < newNumIndices; c++) {
5149:                   for (k = 0; k < dof; k++) {
5150:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5151:                   }
5152:                 }
5153:               }
5154:             }
5155:             else {
5156:               /* copy this row as is */
5157:               for (r = 0; r < dof; r++) {
5158:                 for (c = 0; c < newNumIndices; c++) {
5159:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5160:                 }
5161:               }
5162:             }
5163:             oldOff += dof;
5164:           }
5165:         }
5166:       }
5167:       else {
5168:         PetscInt oldOff = 0;

5170:         for (p = 0; p < numPoints; p++) {
5171:           PetscInt rStart = newPointOffsets[0][p];
5172:           PetscInt b      = points[2 * p];
5173:           PetscInt c, r, k;
5174:           PetscInt dof;

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

5181:             for (r = 0; r < nRows; r++) {
5182:               for (c = 0; c < newNumIndices; c++) {
5183:                 for (k = 0; k < dof; k++) {
5184:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5185:                 }
5186:               }
5187:             }
5188:           }
5189:           else {
5190:             /* copy this row as is */
5191:             for (r = 0; r < dof; r++) {
5192:               for (c = 0; c < newNumIndices; c++) {
5193:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5194:               }
5195:             }
5196:           }
5197:           oldOff += dof;
5198:         }
5199:       }

5201:       DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);
5202:     }
5203:     else {
5204:       newValues = tmpValues;
5205:     }
5206:   }

5208:   /* clean up */
5209:   DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);
5210:   DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);

5212:   if (numFields) {
5213:     for (f = 0; f < numFields; f++) {
5214:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);
5215:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);
5216:       DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);
5217:     }
5218:   }
5219:   else {
5220:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);
5221:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);
5222:     DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);
5223:   }
5224:   ISRestoreIndices(aIS,&anchors);

5226:   /* output */
5227:   if (outPoints) {
5228:     *outPoints = newPoints;
5229:   }
5230:   else {
5231:     DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);
5232:   }
5233:   if (outValues) {
5234:     *outValues = newValues;
5235:   }
5236:   for (f = 0; f <= numFields; f++) {
5237:     offsets[f] = newOffsets[f];
5238:   }
5239:   return(0);
5240: }

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

5245:   Not collective

5247:   Input Parameters:
5248: + dm - The DM
5249: . section - The section describing the layout in v, or NULL to use the default section
5250: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5251: - point - The mesh point

5253:   Output parameters:
5254: + numIndices - The number of indices
5255: . indices - The indices
5256: - outOffsets - Field offset if not NULL

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

5260:   Level: advanced

5262: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5263: @*/
5264: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5265: {
5266:   PetscSection    clSection;
5267:   IS              clPoints;
5268:   const PetscInt *clp;
5269:   const PetscInt  **perms[32] = {NULL};
5270:   PetscInt       *points = NULL, *pointsNew;
5271:   PetscInt        numPoints, numPointsNew;
5272:   PetscInt        offsets[32];
5273:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5274:   PetscErrorCode  ierr;

5282:   PetscSectionGetNumFields(section, &Nf);
5283:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5284:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5285:   /* Get points in closure */
5286:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5287:   /* Get number of indices and indices per field */
5288:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5289:     PetscInt dof, fdof;

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

5330:       for (f = 0; f <= Nf; f++) {
5331:         outOffsets[f] = offsets[f];
5332:       }
5333:     }
5334:     for (p = 0; p < numPoints; p++) {
5335:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5336:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5337:     }
5338:   } else {
5339:     for (p = 0, off = 0; p < numPoints; p++) {
5340:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

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

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

5363:   Not collective

5365:   Input Parameters:
5366: + dm - The DM
5367: . section - The section describing the layout in v, or NULL to use the default section
5368: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5369: . point - The mesh point
5370: . numIndices - The number of indices
5371: . indices - The indices
5372: - outOffsets - Field offset if not NULL

5374:   Level: advanced

5376: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5377: @*/
5378: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5379: {

5385:   DMRestoreWorkArray(dm, 0, PETSC_INT, indices);
5386:   return(0);
5387: }

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

5392:   Not collective

5394:   Input Parameters:
5395: + dm - The DM
5396: . section - The section describing the layout in v, or NULL to use the default section
5397: . globalSection - The section describing the layout in v, or NULL to use the default global section
5398: . A - The matrix
5399: . point - The sieve point in the DM
5400: . values - The array of values
5401: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5406:   Level: intermediate

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

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

5440:     PetscSectionGetDof(section, points[p], &dof);
5441:     for (f = 0; f < numFields; ++f) {
5442:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5443:       offsets[f+1] += fdof;
5444:     }
5445:     numIndices += dof;
5446:   }
5447:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5461:         if (!numFields) {
5462:           PetscSectionGetDof(section,point,&fdof);
5463:         } else {
5464:           PetscSectionGetFieldDof(section,point,f,&fdof);
5465:         }
5466:         if (flip) {
5467:           PetscInt i, j, k;

5469:           if (!valCopy) {
5470:             DMGetWorkArray(dm,numIndices*numIndices,PETSC_SCALAR,&valCopy);
5471:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5472:             values = valCopy;
5473:           }
5474:           for (i = 0; i < fdof; i++) {
5475:             PetscScalar fval = flip[i];

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

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

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

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

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

5634:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5635:     if (!dof) continue;
5636:     for (f = 0; f < numFields; ++f) {
5637:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5638:       foffsets[f+1] += fdof;
5639:     }
5640:     numFIndices += dof;
5641:   }
5642:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5644:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5645:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5646:   DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5647:   DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5648:   if (numFields) {
5649:     const PetscInt **permsF[32] = {NULL};
5650:     const PetscInt **permsC[32] = {NULL};

5652:     for (f = 0; f < numFields; f++) {
5653:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5654:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5655:     }
5656:     for (p = 0; p < numFPoints; p++) {
5657:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5658:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5659:     }
5660:     for (p = 0; p < numCPoints; p++) {
5661:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5662:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5663:     }
5664:     for (f = 0; f < numFields; f++) {
5665:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5666:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5667:     }
5668:   } else {
5669:     const PetscInt **permsF = NULL;
5670:     const PetscInt **permsC = NULL;

5672:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5673:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5674:     for (p = 0, off = 0; p < numFPoints; p++) {
5675:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5677:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5678:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5679:     }
5680:     for (p = 0, off = 0; p < numCPoints; p++) {
5681:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5683:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5684:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5685:     }
5686:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5687:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5688:   }
5689:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5690:   /* TODO: flips */
5691:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5692:   if (ierr) {
5693:     PetscMPIInt    rank;
5694:     PetscErrorCode ierr2;

5696:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5697:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5698:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5699:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5700:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5701: 
5702:   }
5703:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5704:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5705:   DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);
5706:   DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);
5707:   return(0);
5708: }

5710: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5711: {
5712:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5713:   PetscInt      *cpoints = NULL;
5714:   PetscInt       foffsets[32], coffsets[32];
5715:   CellRefiner    cellRefiner;
5716:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

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

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

5786:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5787:     if (!dof) continue;
5788:     for (f = 0; f < numFields; ++f) {
5789:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5790:       foffsets[f+1] += fdof;
5791:     }
5792:     numFIndices += dof;
5793:   }
5794:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

5802:     for (f = 0; f < numFields; f++) {
5803:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5804:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5805:     }
5806:     for (p = 0; p < numFPoints; p++) {
5807:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5808:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5809:     }
5810:     for (p = 0; p < numCPoints; p++) {
5811:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5812:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5813:     }
5814:     for (f = 0; f < numFields; f++) {
5815:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5816:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5817:     }
5818:   } else {
5819:     const PetscInt **permsF = NULL;
5820:     const PetscInt **permsC = NULL;

5822:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5823:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5824:     for (p = 0, off = 0; p < numFPoints; p++) {
5825:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5827:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5828:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5829:     }
5830:     for (p = 0, off = 0; p < numCPoints; p++) {
5831:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5833:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5834:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5835:     }
5836:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5837:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5838:   }
5839:   DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);
5840:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5841:   return(0);
5842: }

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

5847:   Input Parameter:
5848: . dm - The DMPlex object

5850:   Output Parameters:
5851: + cMax - The first hybrid cell
5852: . fMax - The first hybrid face
5853: . eMax - The first hybrid edge
5854: - vMax - The first hybrid vertex

5856:   Level: developer

5858: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5859: @*/
5860: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5861: {
5862:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5863:   PetscInt       dim;

5868:   DMGetDimension(dm, &dim);
5869:   if (cMax) *cMax = mesh->hybridPointMax[dim];
5870:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5871:   if (eMax) *eMax = mesh->hybridPointMax[1];
5872:   if (vMax) *vMax = mesh->hybridPointMax[0];
5873:   return(0);
5874: }

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

5879:   Input Parameters:
5880: . dm   - The DMPlex object
5881: . cMax - The first hybrid cell
5882: . fMax - The first hybrid face
5883: . eMax - The first hybrid edge
5884: - vMax - The first hybrid vertex

5886:   Level: developer

5888: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5889: @*/
5890: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5891: {
5892:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5893:   PetscInt       dim;

5898:   DMGetDimension(dm, &dim);
5899:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5900:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5901:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5902:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5903:   return(0);
5904: }

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

5909:   Input Parameter:
5910: . dm   - The DMPlex object

5912:   Output Parameter:
5913: . cellHeight - The height of a cell

5915:   Level: developer

5917: .seealso DMPlexSetVTKCellHeight()
5918: @*/
5919: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5920: {
5921:   DM_Plex *mesh = (DM_Plex*) dm->data;

5926:   *cellHeight = mesh->vtkCellHeight;
5927:   return(0);
5928: }

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

5933:   Input Parameters:
5934: + dm   - The DMPlex object
5935: - cellHeight - The height of a cell

5937:   Level: developer

5939: .seealso DMPlexGetVTKCellHeight()
5940: @*/
5941: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5942: {
5943:   DM_Plex *mesh = (DM_Plex*) dm->data;

5947:   mesh->vtkCellHeight = cellHeight;
5948:   return(0);
5949: }

5951: /* We can easily have a form that takes an IS instead */
5952: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5953: {
5954:   PetscSection   section, globalSection;
5955:   PetscInt      *numbers, p;

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

5984: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5985: {
5986:   PetscInt       cellHeight, cStart, cEnd, cMax;

5990:   DMPlexGetVTKCellHeight(dm, &cellHeight);
5991:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5992:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5993:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5994:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
5995:   return(0);
5996: }

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

6001:   Input Parameter:
6002: . dm   - The DMPlex object

6004:   Output Parameter:
6005: . globalCellNumbers - Global cell numbers for all cells on this process

6007:   Level: developer

6009: .seealso DMPlexGetVertexNumbering()
6010: @*/
6011: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6012: {
6013:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6018:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6019:   *globalCellNumbers = mesh->globalCellNumbers;
6020:   return(0);
6021: }

6023: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6024: {
6025:   PetscInt       vStart, vEnd, vMax;

6030:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6031:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6032:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6033:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6034:   return(0);
6035: }

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

6040:   Input Parameter:
6041: . dm   - The DMPlex object

6043:   Output Parameter:
6044: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6046:   Level: developer

6048: .seealso DMPlexGetCellNumbering()
6049: @*/
6050: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6051: {
6052:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6057:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6058:   *globalVertexNumbers = mesh->globalVertexNumbers;
6059:   return(0);
6060: }

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

6065:   Input Parameter:
6066: . dm   - The DMPlex object

6068:   Output Parameter:
6069: . globalPointNumbers - Global numbers for all points on this process

6071:   Level: developer

6073: .seealso DMPlexGetCellNumbering()
6074: @*/
6075: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6076: {
6077:   IS             nums[4];
6078:   PetscInt       depths[4];
6079:   PetscInt       depth, d, shift = 0;

6084:   DMPlexGetDepth(dm, &depth);
6085:   /* For unstratified meshes use dim instead of depth */
6086:   if (depth < 0) {DMGetDimension(dm, &depth);}
6087:   depths[0] = depth; depths[1] = 0;
6088:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6089:   for (d = 0; d <= depth; ++d) {
6090:     PetscInt pStart, pEnd, gsize;

6092:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6093:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6094:     shift += gsize;
6095:   }
6096:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6097:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6098:   return(0);
6099: }


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

6105:   Input Parameter:
6106: . dm - The DMPlex object

6108:   Output Parameter:
6109: . ranks - The rank field

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

6114:   Level: intermediate

6116: .seealso: DMView()
6117: @*/
6118: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6119: {
6120:   DM             rdm;
6121:   PetscDS        prob;
6122:   PetscFE        fe;
6123:   PetscScalar   *r;
6124:   PetscMPIInt    rank;
6125:   PetscInt       dim, cStart, cEnd, c;

6129:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6130:   DMClone(dm, &rdm);
6131:   DMGetDimension(rdm, &dim);
6132:   PetscFECreateDefault(rdm, dim, 1, PETSC_TRUE, NULL, -1, &fe);
6133:   PetscObjectSetName((PetscObject) fe, "rank");
6134:   DMGetDS(rdm, &prob);
6135:   PetscDSSetDiscretization(prob, 0, (PetscObject) fe);
6136:   PetscFEDestroy(&fe);
6137:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6138:   DMCreateGlobalVector(rdm, ranks);
6139:   PetscObjectSetName((PetscObject) *ranks, "partition");
6140:   VecGetArray(*ranks, &r);
6141:   for (c = cStart; c < cEnd; ++c) {
6142:     PetscScalar *lr;

6144:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6145:     *lr = rank;
6146:   }
6147:   VecRestoreArray(*ranks, &r);
6148:   DMDestroy(&rdm);
6149:   return(0);
6150: }

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

6155:   Input Parameter:
6156: . dm - The DMPlex object

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

6160:   Level: developer

6162: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6163: @*/
6164: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6165: {
6166:   PetscSection    coneSection, supportSection;
6167:   const PetscInt *cone, *support;
6168:   PetscInt        coneSize, c, supportSize, s;
6169:   PetscInt        pStart, pEnd, p, csize, ssize;
6170:   PetscErrorCode  ierr;

6174:   DMPlexGetConeSection(dm, &coneSection);
6175:   DMPlexGetSupportSection(dm, &supportSection);
6176:   /* Check that point p is found in the support of its cone points, and vice versa */
6177:   DMPlexGetChart(dm, &pStart, &pEnd);
6178:   for (p = pStart; p < pEnd; ++p) {
6179:     DMPlexGetConeSize(dm, p, &coneSize);
6180:     DMPlexGetCone(dm, p, &cone);
6181:     for (c = 0; c < coneSize; ++c) {
6182:       PetscBool dup = PETSC_FALSE;
6183:       PetscInt  d;
6184:       for (d = c-1; d >= 0; --d) {
6185:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6186:       }
6187:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6188:       DMPlexGetSupport(dm, cone[c], &support);
6189:       for (s = 0; s < supportSize; ++s) {
6190:         if (support[s] == p) break;
6191:       }
6192:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6193:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6194:         for (s = 0; s < coneSize; ++s) {
6195:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6196:         }
6197:         PetscPrintf(PETSC_COMM_SELF, "\n");
6198:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6199:         for (s = 0; s < supportSize; ++s) {
6200:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6201:         }
6202:         PetscPrintf(PETSC_COMM_SELF, "\n");
6203:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6204:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6205:       }
6206:     }
6207:     DMPlexGetSupportSize(dm, p, &supportSize);
6208:     DMPlexGetSupport(dm, p, &support);
6209:     for (s = 0; s < supportSize; ++s) {
6210:       DMPlexGetConeSize(dm, support[s], &coneSize);
6211:       DMPlexGetCone(dm, support[s], &cone);
6212:       for (c = 0; c < coneSize; ++c) {
6213:         if (cone[c] == p) break;
6214:       }
6215:       if (c >= coneSize) {
6216:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6217:         for (c = 0; c < supportSize; ++c) {
6218:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6219:         }
6220:         PetscPrintf(PETSC_COMM_SELF, "\n");
6221:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6222:         for (c = 0; c < coneSize; ++c) {
6223:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6224:         }
6225:         PetscPrintf(PETSC_COMM_SELF, "\n");
6226:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6227:       }
6228:     }
6229:   }
6230:   PetscSectionGetStorageSize(coneSection, &csize);
6231:   PetscSectionGetStorageSize(supportSection, &ssize);
6232:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6233:   return(0);
6234: }

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

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

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

6246:   Level: developer

6248: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6249: @*/
6250: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6251: {
6252:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6257:   DMGetDimension(dm, &dim);
6258:   switch (dim) {
6259:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6260:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6261:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6262:   default:
6263:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6264:   }
6265:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6266:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6267:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6268:   cMax = cMax >= 0 ? cMax : cEnd;
6269:   for (c = cStart; c < cMax; ++c) {
6270:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6272:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6273:     for (cl = 0; cl < closureSize*2; cl += 2) {
6274:       const PetscInt p = closure[cl];
6275:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6276:     }
6277:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6278:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6279:   }
6280:   for (c = cMax; c < cEnd; ++c) {
6281:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6283:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6284:     for (cl = 0; cl < closureSize*2; cl += 2) {
6285:       const PetscInt p = closure[cl];
6286:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6287:     }
6288:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6289:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6290:   }
6291:   return(0);
6292: }

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

6297:   Input Parameters:
6298: + dm - The DMPlex object
6299: . isSimplex - Are the cells simplices or tensor products
6300: - cellHeight - Normally 0

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

6304:   Level: developer

6306: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6307: @*/
6308: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6309: {
6310:   PetscInt       pMax[4];
6311:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

6316:   DMGetDimension(dm, &dim);
6317:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6318:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6319:   for (h = cellHeight; h < dim; ++h) {
6320:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6321:     for (c = cStart; c < cEnd; ++c) {
6322:       const PetscInt *cone, *ornt, *faces;
6323:       PetscInt        numFaces, faceSize, coneSize,f;
6324:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6326:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6327:       DMPlexGetConeSize(dm, c, &coneSize);
6328:       DMPlexGetCone(dm, c, &cone);
6329:       DMPlexGetConeOrientation(dm, c, &ornt);
6330:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6331:       for (cl = 0; cl < closureSize*2; cl += 2) {
6332:         const PetscInt p = closure[cl];
6333:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6334:       }
6335:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6336:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6337:       for (f = 0; f < numFaces; ++f) {
6338:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6340:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6341:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6342:           const PetscInt p = fclosure[cl];
6343:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6344:         }
6345:         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);
6346:         for (v = 0; v < fnumCorners; ++v) {
6347:           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]);
6348:         }
6349:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6350:       }
6351:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6352:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6353:     }
6354:   }
6355:   return(0);
6356: }

6358: /* Pointwise interpolation
6359:      Just code FEM for now
6360:      u^f = I u^c
6361:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6362:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6363:      I_{ij} = psi^f_i phi^c_j
6364: */
6365: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6366: {
6367:   PetscSection   gsc, gsf;
6368:   PetscInt       m, n;
6369:   void          *ctx;
6370:   DM             cdm;
6371:   PetscBool      regular;

6375:   DMGetDefaultGlobalSection(dmFine, &gsf);
6376:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6377:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6378:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6380:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6381:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6382:   MatSetType(*interpolation, dmCoarse->mattype);
6383:   DMGetApplicationContext(dmFine, &ctx);

6385:   DMGetCoarseDM(dmFine, &cdm);
6386:   DMPlexGetRegularRefinement(dmFine, &regular);
6387:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6388:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6389:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6390:   /* Use naive scaling */
6391:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6392:   return(0);
6393: }

6395: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6396: {
6398:   VecScatter     ctx;

6401:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6402:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6403:   VecScatterDestroy(&ctx);
6404:   return(0);
6405: }

6407: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6408: {
6409:   PetscSection   section;
6410:   IS            *bcPoints, *bcComps;
6411:   PetscBool     *isFE;
6412:   PetscInt      *bcFields, *numComp, *numDof;
6413:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6414:   PetscInt       cStart, cEnd, cEndInterior;

6418:   DMGetNumFields(dm, &numFields);
6419:   if (!numFields) return(0);
6420:   /* FE and FV boundary conditions are handled slightly differently */
6421:   PetscMalloc1(numFields, &isFE);
6422:   for (f = 0; f < numFields; ++f) {
6423:     PetscObject  obj;
6424:     PetscClassId id;

6426:     DMGetField(dm, f, &obj);
6427:     PetscObjectGetClassId(obj, &id);
6428:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6429:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6430:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6431:   }
6432:   /* Allocate boundary point storage for FEM boundaries */
6433:   DMPlexGetDepth(dm, &depth);
6434:   DMGetDimension(dm, &dim);
6435:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6436:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6437:   PetscDSGetNumBoundary(dm->prob, &numBd);
6438:   for (bd = 0; bd < numBd; ++bd) {
6439:     PetscInt                field;
6440:     DMBoundaryConditionType type;
6441:     const char             *labelName;
6442:     DMLabel                 label;

6444:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6445:     DMGetLabel(dm,labelName,&label);
6446:     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6447:   }
6448:   /* Add ghost cell boundaries for FVM */
6449:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6450:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6451:   /* Constrain ghost cells for FV */
6452:   for (f = 0; f < numFields; ++f) {
6453:     PetscInt *newidx, c;

6455:     if (isFE[f] || cEndInterior < 0) continue;
6456:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6457:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6458:     bcFields[bc] = f;
6459:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6460:   }
6461:   /* Handle FEM Dirichlet boundaries */
6462:   for (bd = 0; bd < numBd; ++bd) {
6463:     const char             *bdLabel;
6464:     DMLabel                 label;
6465:     const PetscInt         *comps;
6466:     const PetscInt         *values;
6467:     PetscInt                bd2, field, numComps, numValues;
6468:     DMBoundaryConditionType type;
6469:     PetscBool               duplicate = PETSC_FALSE;

6471:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6472:     DMGetLabel(dm, bdLabel, &label);
6473:     if (!isFE[field] || !label) continue;
6474:     /* Only want to modify label once */
6475:     for (bd2 = 0; bd2 < bd; ++bd2) {
6476:       const char *bdname;
6477:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6478:       PetscStrcmp(bdname, bdLabel, &duplicate);
6479:       if (duplicate) break;
6480:     }
6481:     if (!duplicate && (isFE[field])) {
6482:       /* don't complete cells, which are just present to give orientation to the boundary */
6483:       DMPlexLabelComplete(dm, label);
6484:     }
6485:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6486:     if (type & DM_BC_ESSENTIAL) {
6487:       PetscInt       *newidx;
6488:       PetscInt        n, newn = 0, p, v;

6490:       bcFields[bc] = field;
6491:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6492:       for (v = 0; v < numValues; ++v) {
6493:         IS              tmp;
6494:         const PetscInt *idx;

6496:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6497:         if (!tmp) continue;
6498:         ISGetLocalSize(tmp, &n);
6499:         ISGetIndices(tmp, &idx);
6500:         if (isFE[field]) {
6501:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6502:         } else {
6503:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6504:         }
6505:         ISRestoreIndices(tmp, &idx);
6506:         ISDestroy(&tmp);
6507:       }
6508:       PetscMalloc1(newn,&newidx);
6509:       newn = 0;
6510:       for (v = 0; v < numValues; ++v) {
6511:         IS              tmp;
6512:         const PetscInt *idx;

6514:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6515:         if (!tmp) continue;
6516:         ISGetLocalSize(tmp, &n);
6517:         ISGetIndices(tmp, &idx);
6518:         if (isFE[field]) {
6519:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6520:         } else {
6521:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6522:         }
6523:         ISRestoreIndices(tmp, &idx);
6524:         ISDestroy(&tmp);
6525:       }
6526:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6527:     }
6528:   }
6529:   /* Handle discretization */
6530:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6531:   for (f = 0; f < numFields; ++f) {
6532:     PetscObject obj;

6534:     DMGetField(dm, f, &obj);
6535:     if (isFE[f]) {
6536:       PetscFE         fe = (PetscFE) obj;
6537:       const PetscInt *numFieldDof;
6538:       PetscInt        d;

6540:       PetscFEGetNumComponents(fe, &numComp[f]);
6541:       PetscFEGetNumDof(fe, &numFieldDof);
6542:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6543:     } else {
6544:       PetscFV fv = (PetscFV) obj;

6546:       PetscFVGetNumComponents(fv, &numComp[f]);
6547:       numDof[f*(dim+1)+dim] = numComp[f];
6548:     }
6549:   }
6550:   for (f = 0; f < numFields; ++f) {
6551:     PetscInt d;
6552:     for (d = 1; d < dim; ++d) {
6553:       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.");
6554:     }
6555:   }
6556:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6557:   for (f = 0; f < numFields; ++f) {
6558:     PetscFE     fe;
6559:     const char *name;

6561:     DMGetField(dm, f, (PetscObject *) &fe);
6562:     PetscObjectGetName((PetscObject) fe, &name);
6563:     PetscSectionSetFieldName(section, f, name);
6564:   }
6565:   DMSetDefaultSection(dm, section);
6566:   PetscSectionDestroy(&section);
6567:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6568:   PetscFree3(bcFields,bcPoints,bcComps);
6569:   PetscFree2(numComp,numDof);
6570:   PetscFree(isFE);
6571:   return(0);
6572: }

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

6577:   Input Parameter:
6578: . dm - The DMPlex object

6580:   Output Parameter:
6581: . regular - The flag

6583:   Level: intermediate

6585: .seealso: DMPlexSetRegularRefinement()
6586: @*/
6587: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6588: {
6592:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6593:   return(0);
6594: }

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

6599:   Input Parameters:
6600: + dm - The DMPlex object
6601: - regular - The flag

6603:   Level: intermediate

6605: .seealso: DMPlexGetRegularRefinement()
6606: @*/
6607: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6608: {
6611:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6612:   return(0);
6613: }

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

6620:   not collective

6622:   Input Parameters:
6623: . dm - The DMPlex object

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


6630:   Level: intermediate

6632: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6633: @*/
6634: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6635: {
6636:   DM_Plex *plex = (DM_Plex *)dm->data;

6641:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6642:   if (anchorSection) *anchorSection = plex->anchorSection;
6643:   if (anchorIS) *anchorIS = plex->anchorIS;
6644:   return(0);
6645: }

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

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

6655:   collective on dm

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

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

6664:   Level: intermediate

6666: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6667: @*/
6668: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6669: {
6670:   DM_Plex        *plex = (DM_Plex *)dm->data;
6671:   PetscMPIInt    result;

6676:   if (anchorSection) {
6678:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6679:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6680:   }
6681:   if (anchorIS) {
6683:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6684:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6685:   }

6687:   PetscObjectReference((PetscObject)anchorSection);
6688:   PetscSectionDestroy(&plex->anchorSection);
6689:   plex->anchorSection = anchorSection;

6691:   PetscObjectReference((PetscObject)anchorIS);
6692:   ISDestroy(&plex->anchorIS);
6693:   plex->anchorIS = anchorIS;

6695: #if defined(PETSC_USE_DEBUG)
6696:   if (anchorIS && anchorSection) {
6697:     PetscInt size, a, pStart, pEnd;
6698:     const PetscInt *anchors;

6700:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6701:     ISGetLocalSize(anchorIS,&size);
6702:     ISGetIndices(anchorIS,&anchors);
6703:     for (a = 0; a < size; a++) {
6704:       PetscInt p;

6706:       p = anchors[a];
6707:       if (p >= pStart && p < pEnd) {
6708:         PetscInt dof;

6710:         PetscSectionGetDof(anchorSection,p,&dof);
6711:         if (dof) {
6712:           PetscErrorCode ierr2;

6714:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6715:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6716:         }
6717:       }
6718:     }
6719:     ISRestoreIndices(anchorIS,&anchors);
6720:   }
6721: #endif
6722:   /* reset the generic constraints */
6723:   DMSetDefaultConstraints(dm,NULL,NULL);
6724:   return(0);
6725: }

6727: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6728: {
6729:   PetscSection anchorSection;
6730:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

6735:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6736:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6737:   PetscSectionGetNumFields(section,&numFields);
6738:   if (numFields) {
6739:     PetscInt f;
6740:     PetscSectionSetNumFields(*cSec,numFields);

6742:     for (f = 0; f < numFields; f++) {
6743:       PetscInt numComp;

6745:       PetscSectionGetFieldComponents(section,f,&numComp);
6746:       PetscSectionSetFieldComponents(*cSec,f,numComp);
6747:     }
6748:   }
6749:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6750:   PetscSectionGetChart(section,&sStart,&sEnd);
6751:   pStart = PetscMax(pStart,sStart);
6752:   pEnd   = PetscMin(pEnd,sEnd);
6753:   pEnd   = PetscMax(pStart,pEnd);
6754:   PetscSectionSetChart(*cSec,pStart,pEnd);
6755:   for (p = pStart; p < pEnd; p++) {
6756:     PetscSectionGetDof(anchorSection,p,&dof);
6757:     if (dof) {
6758:       PetscSectionGetDof(section,p,&dof);
6759:       PetscSectionSetDof(*cSec,p,dof);
6760:       for (f = 0; f < numFields; f++) {
6761:         PetscSectionGetFieldDof(section,p,f,&dof);
6762:         PetscSectionSetFieldDof(*cSec,p,f,dof);
6763:       }
6764:     }
6765:   }
6766:   PetscSectionSetUp(*cSec);
6767:   return(0);
6768: }

6770: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6771: {
6772:   PetscSection aSec;
6773:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6774:   const PetscInt *anchors;
6775:   PetscInt numFields, f;
6776:   IS aIS;

6781:   PetscSectionGetStorageSize(cSec, &m);
6782:   PetscSectionGetStorageSize(section, &n);
6783:   MatCreate(PETSC_COMM_SELF,cMat);
6784:   MatSetSizes(*cMat,m,n,m,n);
6785:   MatSetType(*cMat,MATSEQAIJ);
6786:   DMPlexGetAnchors(dm,&aSec,&aIS);
6787:   ISGetIndices(aIS,&anchors);
6788:   /* cSec will be a subset of aSec and section */
6789:   PetscSectionGetChart(cSec,&pStart,&pEnd);
6790:   PetscMalloc1(m+1,&i);
6791:   i[0] = 0;
6792:   PetscSectionGetNumFields(section,&numFields);
6793:   for (p = pStart; p < pEnd; p++) {
6794:     PetscInt rDof, rOff, r;

6796:     PetscSectionGetDof(aSec,p,&rDof);
6797:     if (!rDof) continue;
6798:     PetscSectionGetOffset(aSec,p,&rOff);
6799:     if (numFields) {
6800:       for (f = 0; f < numFields; f++) {
6801:         annz = 0;
6802:         for (r = 0; r < rDof; r++) {
6803:           a = anchors[rOff + r];
6804:           PetscSectionGetFieldDof(section,a,f,&aDof);
6805:           annz += aDof;
6806:         }
6807:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6808:         PetscSectionGetFieldOffset(cSec,p,f,&off);
6809:         for (q = 0; q < dof; q++) {
6810:           i[off + q + 1] = i[off + q] + annz;
6811:         }
6812:       }
6813:     }
6814:     else {
6815:       annz = 0;
6816:       for (q = 0; q < dof; q++) {
6817:         a = anchors[off + q];
6818:         PetscSectionGetDof(section,a,&aDof);
6819:         annz += aDof;
6820:       }
6821:       PetscSectionGetDof(cSec,p,&dof);
6822:       PetscSectionGetOffset(cSec,p,&off);
6823:       for (q = 0; q < dof; q++) {
6824:         i[off + q + 1] = i[off + q] + annz;
6825:       }
6826:     }
6827:   }
6828:   nnz = i[m];
6829:   PetscMalloc1(nnz,&j);
6830:   offset = 0;
6831:   for (p = pStart; p < pEnd; p++) {
6832:     if (numFields) {
6833:       for (f = 0; f < numFields; f++) {
6834:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6835:         for (q = 0; q < dof; q++) {
6836:           PetscInt rDof, rOff, r;
6837:           PetscSectionGetDof(aSec,p,&rDof);
6838:           PetscSectionGetOffset(aSec,p,&rOff);
6839:           for (r = 0; r < rDof; r++) {
6840:             PetscInt s;

6842:             a = anchors[rOff + r];
6843:             PetscSectionGetFieldDof(section,a,f,&aDof);
6844:             PetscSectionGetFieldOffset(section,a,f,&aOff);
6845:             for (s = 0; s < aDof; s++) {
6846:               j[offset++] = aOff + s;
6847:             }
6848:           }
6849:         }
6850:       }
6851:     }
6852:     else {
6853:       PetscSectionGetDof(cSec,p,&dof);
6854:       for (q = 0; q < dof; q++) {
6855:         PetscInt rDof, rOff, r;
6856:         PetscSectionGetDof(aSec,p,&rDof);
6857:         PetscSectionGetOffset(aSec,p,&rOff);
6858:         for (r = 0; r < rDof; r++) {
6859:           PetscInt s;

6861:           a = anchors[rOff + r];
6862:           PetscSectionGetDof(section,a,&aDof);
6863:           PetscSectionGetOffset(section,a,&aOff);
6864:           for (s = 0; s < aDof; s++) {
6865:             j[offset++] = aOff + s;
6866:           }
6867:         }
6868:       }
6869:     }
6870:   }
6871:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
6872:   PetscFree(i);
6873:   PetscFree(j);
6874:   ISRestoreIndices(aIS,&anchors);
6875:   return(0);
6876: }

6878: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6879: {
6880:   DM_Plex        *plex = (DM_Plex *)dm->data;
6881:   PetscSection   anchorSection, section, cSec;
6882:   Mat            cMat;

6887:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6888:   if (anchorSection) {
6889:     PetscDS  ds;
6890:     PetscInt nf;

6892:     DMGetDefaultSection(dm,&section);
6893:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
6894:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
6895:     DMGetDS(dm,&ds);
6896:     PetscDSGetNumFields(ds,&nf);
6897:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
6898:     DMSetDefaultConstraints(dm,cSec,cMat);
6899:     PetscSectionDestroy(&cSec);
6900:     MatDestroy(&cMat);
6901:   }
6902:   return(0);
6903: }