Actual source code: plex.c

petsc-3.9.4 2018-09-11
Report Typos and Errors
  1:  #include <petsc/private/dmpleximpl.h>
  2:  #include <petsc/private/isimpl.h>
  3:  #include <petsc/private/vecimpl.h>
  4:  #include <petsc/private/glvisvecimpl.h>
  5:  #include <petscsf.h>
  6:  #include <petscds.h>
  7:  #include <petscdraw.h>

  9: /* Logging support */
 10: 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;

 12: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

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

 18:   Collective

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

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

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

 28:   Level: intermediate

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

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

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

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

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

147:   PetscViewerDrawGetDraw(viewer, 0, &draw);
148:   PetscDrawIsNull(draw, &isnull);
149:   if (isnull) return(0);

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

163:   PetscObjectGetName((PetscObject) v, &name);
164:   DMGetOutputSequenceNumber(dm, &step, &time);

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

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

183:     PetscSectionGetFieldComponents(s, f, &Nc);
184:     PetscSectionGetFieldName(s, f, &fname);

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

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

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

213:       VecGetArrayRead(fv, &array);
214:       for (c = cStart; c < cEnd; ++c) {
215:         PetscScalar *coords = NULL, *a = NULL;
216:         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};

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

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

268: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
269: {
270:   DM                      dm;
271:   Vec                     locv;
272:   const char              *name;
273:   PetscSection            section;
274:   PetscInt                pStart, pEnd;
275:   PetscViewerVTKFieldType ft;
276:   PetscErrorCode          ierr;

279:   VecGetDM(v, &dm);
280:   DMCreateLocalVector(dm, &locv); /* VTK viewer requires exclusive ownership of the vector */
281:   PetscObjectGetName((PetscObject) v, &name);
282:   PetscObjectSetName((PetscObject) locv, name);
283:   VecCopy(v, locv);
284:   DMGetDefaultSection(dm, &section);
285:   DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);
286:   PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) locv);
287:   return(0);
288: }

290: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
291: {
292:   DM             dm;
293:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

297:   VecGetDM(v, &dm);
298:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
299:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
300:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
301:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
302:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
303:   if (isvtk || ishdf5 || isdraw || isglvis) {
304:     PetscInt    i,numFields;
305:     PetscObject fe;
306:     PetscBool   fem = PETSC_FALSE;
307:     Vec         locv = v;
308:     const char  *name;
309:     PetscInt    step;
310:     PetscReal   time;

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

344:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
345:     if (isseq) {VecView_Seq(v, viewer);}
346:     else       {VecView_MPI(v, viewer);}
347:   }
348:   return(0);
349: }

351: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
352: {
353:   DM             dm;
354:   PetscBool      isvtk, ishdf5, isdraw, isglvis;

358:   VecGetDM(v, &dm);
359:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
360:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
361:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
362:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
363:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
364:   if (isvtk || isdraw || isglvis) {
365:     Vec         locv;
366:     const char *name;

368:     DMGetLocalVector(dm, &locv);
369:     PetscObjectGetName((PetscObject) v, &name);
370:     PetscObjectSetName((PetscObject) locv, name);
371:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
372:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
373:     VecView_Plex_Local(locv, viewer);
374:     DMRestoreLocalVector(dm, &locv);
375:   } else if (ishdf5) {
376: #if defined(PETSC_HAVE_HDF5)
377:     VecView_Plex_HDF5_Internal(v, viewer);
378: #else
379:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
380: #endif
381:   } else {
382:     PetscBool isseq;

384:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
385:     if (isseq) {VecView_Seq(v, viewer);}
386:     else       {VecView_MPI(v, viewer);}
387:   }
388:   return(0);
389: }

391: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
392: {
393:   DM                dm;
394:   MPI_Comm          comm;
395:   PetscViewerFormat format;
396:   Vec               v;
397:   PetscBool         isvtk, ishdf5;
398:   PetscErrorCode    ierr;

401:   VecGetDM(originalv, &dm);
402:   PetscObjectGetComm((PetscObject) originalv, &comm);
403:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
404:   PetscViewerGetFormat(viewer, &format);
405:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
406:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
407:   if (format == PETSC_VIEWER_NATIVE) {
408:     const char *vecname;
409:     PetscInt    n, nroots;

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

437:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
438:     if (isseq) {VecView_Seq(v, viewer);}
439:     else       {VecView_MPI(v, viewer);}
440:   }
441:   if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
442:   return(0);
443: }

445: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
446: {
447:   DM             dm;
448:   PetscBool      ishdf5;

452:   VecGetDM(v, &dm);
453:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
454:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
455:   if (ishdf5) {
456:     DM          dmBC;
457:     Vec         gv;
458:     const char *name;

460:     DMGetOutputDM(dm, &dmBC);
461:     DMGetGlobalVector(dmBC, &gv);
462:     PetscObjectGetName((PetscObject) v, &name);
463:     PetscObjectSetName((PetscObject) gv, name);
464:     VecLoad_Default(gv, viewer);
465:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
466:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
467:     DMRestoreGlobalVector(dmBC, &gv);
468:   } else {
469:     VecLoad_Default(v, viewer);
470:   }
471:   return(0);
472: }

474: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
475: {
476:   DM             dm;
477:   PetscBool      ishdf5;

481:   VecGetDM(v, &dm);
482:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
483:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
484:   if (ishdf5) {
485: #if defined(PETSC_HAVE_HDF5)
486:     VecLoad_Plex_HDF5_Internal(v, viewer);
487: #else
488:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
489: #endif
490:   } else {
491:     VecLoad_Default(v, viewer);
492:   }
493:   return(0);
494: }

496: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
497: {
498:   DM                dm;
499:   PetscViewerFormat format;
500:   PetscBool         ishdf5;
501:   PetscErrorCode    ierr;

504:   VecGetDM(originalv, &dm);
505:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
506:   PetscViewerGetFormat(viewer, &format);
507:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
508:   if (format == PETSC_VIEWER_NATIVE) {
509:     if (dm->sfNatural) {
510:       if (ishdf5) {
511: #if defined(PETSC_HAVE_HDF5)
512:         Vec         v;
513:         const char *vecname;

515:         DMGetGlobalVector(dm, &v);
516:         PetscObjectGetName((PetscObject) originalv, &vecname);
517:         PetscObjectSetName((PetscObject) v, vecname);
518:         VecLoad_Plex_HDF5_Native_Internal(v, viewer);
519:         DMPlexNaturalToGlobalBegin(dm, v, originalv);
520:         DMPlexNaturalToGlobalEnd(dm, v, originalv);
521:         DMRestoreGlobalVector(dm, &v);
522: #else
523:         SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
524: #endif
525:       } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
526:     }
527:   }
528:   return(0);
529: }

531: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
532: {
533:   PetscSection       coordSection;
534:   Vec                coordinates;
535:   DMLabel            depthLabel;
536:   const char        *name[4];
537:   const PetscScalar *a;
538:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
539:   PetscErrorCode     ierr;

542:   DMGetDimension(dm, &dim);
543:   DMGetCoordinatesLocal(dm, &coordinates);
544:   DMGetCoordinateSection(dm, &coordSection);
545:   DMPlexGetDepthLabel(dm, &depthLabel);
546:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
547:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
548:   VecGetArrayRead(coordinates, &a);
549:   name[0]     = "vertex";
550:   name[1]     = "edge";
551:   name[dim-1] = "face";
552:   name[dim]   = "cell";
553:   for (c = cStart; c < cEnd; ++c) {
554:     PetscInt *closure = NULL;
555:     PetscInt  closureSize, cl;

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

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

586: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
587: {
588:   DM_Plex          *mesh = (DM_Plex*) dm->data;
589:   DM                cdm;
590:   DMLabel           markers;
591:   PetscSection      coordSection;
592:   Vec               coordinates;
593:   PetscViewerFormat format;
594:   PetscErrorCode    ierr;

597:   DMGetCoordinateDM(dm, &cdm);
598:   DMGetDefaultSection(cdm, &coordSection);
599:   DMGetCoordinatesLocal(dm, &coordinates);
600:   PetscViewerGetFormat(viewer, &format);
601:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
602:     const char *name;
603:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
604:     PetscInt    pStart, pEnd, p;
605:     PetscMPIInt rank, size;

607:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
608:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
609:     PetscObjectGetName((PetscObject) dm, &name);
610:     DMPlexGetChart(dm, &pStart, &pEnd);
611:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
612:     DMGetDimension(dm, &dim);
613:     DMPlexGetVTKCellHeight(dm, &cellHeight);
614:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
615:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
616:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
617:     PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
618:     PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
619:     PetscViewerASCIIPushSynchronized(viewer);
620:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);
621:     for (p = pStart; p < pEnd; ++p) {
622:       PetscInt dof, off, s;

624:       PetscSectionGetDof(mesh->supportSection, p, &dof);
625:       PetscSectionGetOffset(mesh->supportSection, p, &off);
626:       for (s = off; s < off+dof; ++s) {
627:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
628:       }
629:     }
630:     PetscViewerFlush(viewer);
631:     PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
632:     for (p = pStart; p < pEnd; ++p) {
633:       PetscInt dof, off, c;

635:       PetscSectionGetDof(mesh->coneSection, p, &dof);
636:       PetscSectionGetOffset(mesh->coneSection, p, &off);
637:       for (c = off; c < off+dof; ++c) {
638:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
639:       }
640:     }
641:     PetscViewerFlush(viewer);
642:     PetscViewerASCIIPopSynchronized(viewer);
643:     PetscSectionGetChart(coordSection, &pStart, NULL);
644:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
645:     DMGetLabel(dm, "marker", &markers);
646:     DMLabelView(markers,viewer);
647:     if (size > 1) {
648:       PetscSF sf;

650:       DMGetPointSF(dm, &sf);
651:       PetscSFView(sf, viewer);
652:     }
653:     PetscViewerFlush(viewer);
654:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
655:     const char  *name, *color;
656:     const char  *defcolors[3]  = {"gray", "orange", "green"};
657:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
658:     PetscReal    scale         = 2.0;
659:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
660:     double       tcoords[3];
661:     PetscScalar *coords;
662:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
663:     PetscMPIInt  rank, size;
664:     char         **names, **colors, **lcolors;

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

717:       PetscSectionGetDof(coordSection, v, &dof);
718:       PetscSectionGetOffset(coordSection, v, &off);
719:       PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");
720:       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
721:       for (d = 0; d < dof; ++d) {
722:         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
723:         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
724:       }
725:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
726:       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
727:       for (d = 0; d < dof; ++d) {
728:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
729:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);
730:       }
731:       color = colors[rank%numColors];
732:       for (l = 0; l < numLabels; ++l) {
733:         PetscInt val;
734:         DMGetLabelValue(dm, names[l], v, &val);
735:         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
736:       }
737:       if (useNumbers) {
738:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);
739:       } else {
740:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);
741:       }
742:     }
743:     VecRestoreArray(coordinates, &coords);
744:     PetscViewerFlush(viewer);
745:     /* Plot edges */
746:     if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
747:     if (dim < 3 && useNumbers) {
748:       VecGetArray(coordinates, &coords);
749:       PetscViewerASCIIPrintf(viewer, "\\path\n");
750:       for (e = eStart; e < eEnd; ++e) {
751:         const PetscInt *cone;
752:         PetscInt        coneSize, offA, offB, dof, d;

754:         DMPlexGetConeSize(dm, e, &coneSize);
755:         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
756:         DMPlexGetCone(dm, e, &cone);
757:         PetscSectionGetDof(coordSection, cone[0], &dof);
758:         PetscSectionGetOffset(coordSection, cone[0], &offA);
759:         PetscSectionGetOffset(coordSection, cone[1], &offB);
760:         PetscViewerASCIISynchronizedPrintf(viewer, "(");
761:         for (d = 0; d < dof; ++d) {
762:           tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
763:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
764:         }
765:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
766:         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
767:         for (d = 0; d < dof; ++d) {
768:           if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
769:           PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);
770:         }
771:         color = colors[rank%numColors];
772:         for (l = 0; l < numLabels; ++l) {
773:           PetscInt val;
774:           DMGetLabelValue(dm, names[l], v, &val);
775:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
776:         }
777:         PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);
778:       }
779:       VecRestoreArray(coordinates, &coords);
780:       PetscViewerFlush(viewer);
781:       PetscViewerASCIIPrintf(viewer, "(0,0);\n");
782:     }
783:     /* Plot cells */
784:     if (dim == 3 || !useNumbers) {
785:       for (e = eStart; e < eEnd; ++e) {
786:         const PetscInt *cone;

788:         color = colors[rank%numColors];
789:         for (l = 0; l < numLabels; ++l) {
790:           PetscInt val;
791:           DMGetLabelValue(dm, names[l], e, &val);
792:           if (val >= 0) {color = lcolors[l%numLColors]; break;}
793:         }
794:         DMPlexGetCone(dm, e, &cone);
795:         PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);
796:       }
797:     } else {
798:       DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
799:       for (c = cStart; c < cEnd; ++c) {
800:         PetscInt *closure = NULL;
801:         PetscInt  closureSize, firstPoint = -1;

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

808:           if ((point < vStart) || (point >= vEnd)) continue;
809:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
810:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
811:           if (firstPoint < 0) firstPoint = point;
812:         }
813:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
814:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
815:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
816:       }
817:     }
818:     PetscViewerFlush(viewer);
819:     PetscViewerASCIIPopSynchronized(viewer);
820:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
821:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
822:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
823:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
824:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
825:     PetscFree3(names, colors, lcolors);
826:   } else {
827:     MPI_Comm    comm;
828:     PetscInt   *sizes, *hybsizes;
829:     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
830:     PetscInt    pStart, pEnd, p;
831:     PetscInt    numLabels, l;
832:     const char *name;
833:     PetscMPIInt size;

835:     PetscObjectGetComm((PetscObject)dm,&comm);
836:     MPI_Comm_size(comm, &size);
837:     DMGetDimension(dm, &dim);
838:     DMPlexGetVTKCellHeight(dm, &cellHeight);
839:     PetscObjectGetName((PetscObject) dm, &name);
840:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
841:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
842:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
843:     DMPlexGetDepth(dm, &locDepth);
844:     MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
845:     DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);
846:     PetscMalloc2(size,&sizes,size,&hybsizes);
847:     if (depth == 1) {
848:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
849:       pEnd = pEnd - pStart;
850:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
851:       PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);
852:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
853:       PetscViewerASCIIPrintf(viewer, "\n");
854:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
855:       pEnd = pEnd - pStart;
856:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
857:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
858:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
859:       PetscViewerASCIIPrintf(viewer, "\n");
860:     } else {
861:       PetscMPIInt rank;
862:       MPI_Comm_rank(comm, &rank);
863:       for (d = 0; d <= dim; d++) {
864:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
865:         pEnd    -= pStart;
866:         pMax[d] -= pStart;
867:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
868:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
869:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
870:         for (p = 0; p < size; ++p) {
871:           if (!rank) {
872:             if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
873:             else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
874:           }
875:         }
876:         PetscViewerASCIIPrintf(viewer, "\n");
877:       }
878:     }
879:     PetscFree2(sizes,hybsizes);
880:     DMGetNumLabels(dm, &numLabels);
881:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
882:     for (l = 0; l < numLabels; ++l) {
883:       DMLabel         label;
884:       const char     *name;
885:       IS              valueIS;
886:       const PetscInt *values;
887:       PetscInt        numValues, v;

889:       DMGetLabelName(dm, l, &name);
890:       DMGetLabel(dm, name, &label);
891:       DMLabelGetNumValues(label, &numValues);
892:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
893:       DMLabelGetValueIS(label, &valueIS);
894:       ISGetIndices(valueIS, &values);
895:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
896:       for (v = 0; v < numValues; ++v) {
897:         PetscInt size;

899:         DMLabelGetStratumSize(label, values[v], &size);
900:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
901:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
902:       }
903:       PetscViewerASCIIPrintf(viewer, ")\n");
904:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
905:       ISRestoreIndices(valueIS, &values);
906:       ISDestroy(&valueIS);
907:     }
908:     DMGetCoarseDM(dm, &cdm);
909:     if (cdm) {
910:       PetscViewerASCIIPushTab(viewer);
911:       DMPlexView_Ascii(cdm, viewer);
912:       PetscViewerASCIIPopTab(viewer);
913:     }
914:   }
915:   return(0);
916: }

918: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
919: {
920:   PetscDraw          draw;
921:   DM                 cdm;
922:   PetscSection       coordSection;
923:   Vec                coordinates;
924:   const PetscScalar *coords;
925:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
926:   PetscBool          isnull;
927:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
928:   PetscErrorCode     ierr;

931:   DMGetCoordinateDim(dm, &dim);
932:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
933:   DMGetCoordinateDM(dm, &cdm);
934:   DMGetDefaultSection(cdm, &coordSection);
935:   DMGetCoordinatesLocal(dm, &coordinates);
936:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
937:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

939:   PetscViewerDrawGetDraw(viewer, 0, &draw);
940:   PetscDrawIsNull(draw, &isnull);
941:   if (isnull) return(0);
942:   PetscDrawSetTitle(draw, "Mesh");

944:   VecGetLocalSize(coordinates, &N);
945:   VecGetArrayRead(coordinates, &coords);
946:   for (c = 0; c < N; c += dim) {
947:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
948:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
949:   }
950:   VecRestoreArrayRead(coordinates, &coords);
951:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
952:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
953:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
954:   PetscDrawClear(draw);

956:   for (c = cStart; c < cEnd; ++c) {
957:     PetscScalar *coords = NULL;
958:     PetscInt     numCoords,coneSize;

960:     DMPlexGetConeSize(dm, c, &coneSize);
961:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
962:     switch (coneSize) {
963:     case 3:
964:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
965:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
966:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
967:       break;
968:     case 4:
969:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
970:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
971:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
972:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
973:       break;
974:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
975:     }
976:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
977:   }
978:   PetscDrawFlush(draw);
979:   PetscDrawPause(draw);
980:   PetscDrawSave(draw);
981:   return(0);
982: }

984: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
985: {
986:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
987:   PetscErrorCode    ierr;

992:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
993:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
994:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
995:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
996:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
997:   if (iascii) {
998:     PetscViewerFormat format;
999:     PetscViewerGetFormat(viewer, &format);
1000:     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1001:       DMPlexView_GLVis(dm, viewer);
1002:     } else {
1003:       DMPlexView_Ascii(dm, viewer);
1004:     }
1005:   } else if (ishdf5) {
1006: #if defined(PETSC_HAVE_HDF5)
1007:     PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
1008:     DMPlexView_HDF5_Internal(dm, viewer);
1009:     PetscViewerPopFormat(viewer);
1010: #else
1011:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1012: #endif
1013:   } else if (isvtk) {
1014:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
1015:   } else if (isdraw) {
1016:     DMPlexView_Draw(dm, viewer);
1017:   } else if (isglvis) {
1018:     DMPlexView_GLVis(dm, viewer);
1019:   }
1020:   /* Optionally view the partition */
1021:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1022:   if (flg) {
1023:     Vec ranks;
1024:     DMPlexCreateRankField(dm, &ranks);
1025:     VecView(ranks, viewer);
1026:     VecDestroy(&ranks);
1027:   }
1028:   return(0);
1029: }

1031: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1032: {
1033:   PetscBool      isbinary, ishdf5;

1039:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
1040:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
1041:   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
1042:   else if (ishdf5) {
1043: #if defined(PETSC_HAVE_HDF5)
1044:     DMPlexLoad_HDF5_Internal(dm, viewer);
1045: #else
1046:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1047: #endif
1048:   }
1049:   return(0);
1050: }

1052: PetscErrorCode DMDestroy_Plex(DM dm)
1053: {
1054:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1058:   PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1059:   PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1060:   if (--mesh->refct > 0) return(0);
1061:   PetscSectionDestroy(&mesh->coneSection);
1062:   PetscFree(mesh->cones);
1063:   PetscFree(mesh->coneOrientations);
1064:   PetscSectionDestroy(&mesh->supportSection);
1065:   PetscSectionDestroy(&mesh->subdomainSection);
1066:   PetscFree(mesh->supports);
1067:   PetscFree(mesh->facesTmp);
1068:   PetscFree(mesh->tetgenOpts);
1069:   PetscFree(mesh->triangleOpts);
1070:   PetscPartitionerDestroy(&mesh->partitioner);
1071:   DMLabelDestroy(&mesh->subpointMap);
1072:   ISDestroy(&mesh->globalVertexNumbers);
1073:   ISDestroy(&mesh->globalCellNumbers);
1074:   PetscSectionDestroy(&mesh->anchorSection);
1075:   ISDestroy(&mesh->anchorIS);
1076:   PetscSectionDestroy(&mesh->parentSection);
1077:   PetscFree(mesh->parents);
1078:   PetscFree(mesh->childIDs);
1079:   PetscSectionDestroy(&mesh->childSection);
1080:   PetscFree(mesh->children);
1081:   DMDestroy(&mesh->referenceTree);
1082:   PetscGridHashDestroy(&mesh->lbox);
1083:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1084:   PetscFree(mesh);
1085:   return(0);
1086: }

1088: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1089: {
1090:   PetscSection           sectionGlobal;
1091:   PetscInt               bs = -1, mbs;
1092:   PetscInt               localSize;
1093:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1094:   PetscErrorCode         ierr;
1095:   MatType                mtype;
1096:   ISLocalToGlobalMapping ltog;

1099:   MatInitializePackage();
1100:   mtype = dm->mattype;
1101:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
1102:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1103:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1104:   MatCreate(PetscObjectComm((PetscObject)dm), J);
1105:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1106:   MatSetType(*J, mtype);
1107:   MatSetFromOptions(*J);
1108:   MatGetBlockSize(*J, &mbs);
1109:   if (mbs > 1) bs = mbs;
1110:   PetscStrcmp(mtype, MATSHELL, &isShell);
1111:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
1112:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1113:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1114:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1115:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1116:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1117:   PetscStrcmp(mtype, MATIS, &isMatIS);
1118:   if (!isShell) {
1119:     PetscSection subSection;
1120:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1121:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1122:     PetscInt     pStart, pEnd, p, dof, cdof;

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

1129:       DMGetDefaultSection(dm, &section);
1130:       PetscSectionGetStorageSize(section, &size);
1131:       PetscMalloc1(size,&ltogidx);
1132:       DMPlexGetSubdomainSection(dm, &subSection);
1133:     } else {
1134:       DMGetLocalToGlobalMapping(dm,&ltog);
1135:     }
1136:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1137:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1138:       PetscInt bdof;

1140:       PetscSectionGetDof(sectionGlobal, p, &dof);
1141:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1142:       dof  = dof < 0 ? -(dof+1) : dof;
1143:       bdof = cdof && (dof-cdof) ? 1 : dof;
1144:       if (dof) {
1145:         if (bs < 0)          {bs = bdof;}
1146:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1147:       }
1148:       if (isMatIS) {
1149:         PetscInt loff,c,off;
1150:         PetscSectionGetOffset(subSection, p, &loff);
1151:         PetscSectionGetOffset(sectionGlobal, p, &off);
1152:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1153:       }
1154:     }
1155:     /* Must have same blocksize on all procs (some might have no points) */
1156:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1157:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1158:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1159:     else                            {bs = bsMinMax[0];}
1160:     bs = bs < 0 ? 1 : bs;
1161:     if (isMatIS) {
1162:       PetscInt l;
1163:       /* Must reduce indices by blocksize */
1164:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1165:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1166:     }
1167:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1168:     if (isMatIS) {
1169:       ISLocalToGlobalMappingDestroy(&ltog);
1170:     }
1171:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1172:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1173:     PetscFree4(dnz, onz, dnzu, onzu);
1174:   }
1175:   MatSetDM(*J, dm);
1176:   return(0);
1177: }

1179: /*@
1180:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1182:   Not collective

1184:   Input Parameter:
1185: . mesh - The DMPlex

1187:   Output Parameters:
1188: . subsection - The subdomain section

1190:   Level: developer

1192: .seealso:
1193: @*/
1194: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1195: {
1196:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1201:   if (!mesh->subdomainSection) {
1202:     PetscSection section;
1203:     PetscSF      sf;

1205:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1206:     DMGetDefaultSection(dm,&section);
1207:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1208:     PetscSFDestroy(&sf);
1209:   }
1210:   *subsection = mesh->subdomainSection;
1211:   return(0);
1212: }

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

1217:   Not collective

1219:   Input Parameter:
1220: . mesh - The DMPlex

1222:   Output Parameters:
1223: + pStart - The first mesh point
1224: - pEnd   - The upper bound for mesh points

1226:   Level: beginner

1228: .seealso: DMPlexCreate(), DMPlexSetChart()
1229: @*/
1230: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1231: {
1232:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1237:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1238:   return(0);
1239: }

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

1244:   Not collective

1246:   Input Parameters:
1247: + mesh - The DMPlex
1248: . pStart - The first mesh point
1249: - pEnd   - The upper bound for mesh points

1251:   Output Parameters:

1253:   Level: beginner

1255: .seealso: DMPlexCreate(), DMPlexGetChart()
1256: @*/
1257: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1258: {
1259:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1264:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1265:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1266:   return(0);
1267: }

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

1272:   Not collective

1274:   Input Parameters:
1275: + mesh - The DMPlex
1276: - p - The point, which must lie in the chart set with DMPlexSetChart()

1278:   Output Parameter:
1279: . size - The cone size for point p

1281:   Level: beginner

1283: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1284: @*/
1285: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1286: {
1287:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1293:   PetscSectionGetDof(mesh->coneSection, p, size);
1294:   return(0);
1295: }

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

1300:   Not collective

1302:   Input Parameters:
1303: + mesh - The DMPlex
1304: . p - The point, which must lie in the chart set with DMPlexSetChart()
1305: - size - The cone size for point p

1307:   Output Parameter:

1309:   Note:
1310:   This should be called after DMPlexSetChart().

1312:   Level: beginner

1314: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1315: @*/
1316: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1317: {
1318:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1325:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1326:   return(0);
1327: }

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

1332:   Not collective

1334:   Input Parameters:
1335: + mesh - The DMPlex
1336: . p - The point, which must lie in the chart set with DMPlexSetChart()
1337: - size - The additional cone size for point p

1339:   Output Parameter:

1341:   Note:
1342:   This should be called after DMPlexSetChart().

1344:   Level: beginner

1346: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1347: @*/
1348: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1349: {
1350:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1351:   PetscInt       csize;

1356:   PetscSectionAddDof(mesh->coneSection, p, size);
1357:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1359:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1360:   return(0);
1361: }

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

1366:   Not collective

1368:   Input Parameters:
1369: + mesh - The DMPlex
1370: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1375:   Level: beginner

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

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

1383: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1384: @*/
1385: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1386: {
1387:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1388:   PetscInt       off;

1394:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1395:   *cone = &mesh->cones[off];
1396:   return(0);
1397: }

1399: /*@
1400:   DMPlexSetCone - Set the points on the in-edges for this point in the DAG

1402:   Not collective

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

1409:   Output Parameter:

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

1414:   Level: beginner

1416: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1417: @*/
1418: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1419: {
1420:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1421:   PetscInt       pStart, pEnd;
1422:   PetscInt       dof, off, c;

1427:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1428:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1430:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1431:   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);
1432:   for (c = 0; c < dof; ++c) {
1433:     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);
1434:     mesh->cones[off+c] = cone[c];
1435:   }
1436:   return(0);
1437: }

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

1442:   Not collective

1444:   Input Parameters:
1445: + mesh - The DMPlex
1446: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1454:   Level: beginner

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

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

1462: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1463: @*/
1464: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1465: {
1466:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1467:   PetscInt       off;

1472: #if defined(PETSC_USE_DEBUG)
1473:   {
1474:     PetscInt dof;
1475:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1477:   }
1478: #endif
1479:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1481:   *coneOrientation = &mesh->coneOrientations[off];
1482:   return(0);
1483: }

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

1488:   Not collective

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

1498:   Output Parameter:

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

1503:   Level: beginner

1505: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1506: @*/
1507: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1508: {
1509:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1510:   PetscInt       pStart, pEnd;
1511:   PetscInt       dof, off, c;

1516:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1517:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1519:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1520:   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);
1521:   for (c = 0; c < dof; ++c) {
1522:     PetscInt cdof, o = coneOrientation[c];

1524:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1525:     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);
1526:     mesh->coneOrientations[off+c] = o;
1527:   }
1528:   return(0);
1529: }

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

1534:   Not collective

1536:   Input Parameters:
1537: + mesh - The DMPlex
1538: . p - The point, which must lie in the chart set with DMPlexSetChart()
1539: . conePos - The local index in the cone where the point should be put
1540: - conePoint - The mesh point to insert

1542:   Level: beginner

1544: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1545: @*/
1546: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1547: {
1548:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1549:   PetscInt       pStart, pEnd;
1550:   PetscInt       dof, off;

1555:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1556:   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);
1557:   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);
1558:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1559:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1560:   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);
1561:   mesh->cones[off+conePos] = conePoint;
1562:   return(0);
1563: }

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

1568:   Not collective

1570:   Input Parameters:
1571: + mesh - The DMPlex
1572: . p - The point, which must lie in the chart set with DMPlexSetChart()
1573: . conePos - The local index in the cone where the point should be put
1574: - coneOrientation - The point orientation to insert

1576:   Level: beginner

1578: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1579: @*/
1580: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1581: {
1582:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1583:   PetscInt       pStart, pEnd;
1584:   PetscInt       dof, off;

1589:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1590:   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);
1591:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1592:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1593:   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);
1594:   mesh->coneOrientations[off+conePos] = coneOrientation;
1595:   return(0);
1596: }

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

1601:   Not collective

1603:   Input Parameters:
1604: + mesh - The DMPlex
1605: - p - The point, which must lie in the chart set with DMPlexSetChart()

1607:   Output Parameter:
1608: . size - The support size for point p

1610:   Level: beginner

1612: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1613: @*/
1614: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1615: {
1616:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1622:   PetscSectionGetDof(mesh->supportSection, p, size);
1623:   return(0);
1624: }

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

1629:   Not collective

1631:   Input Parameters:
1632: + mesh - The DMPlex
1633: . p - The point, which must lie in the chart set with DMPlexSetChart()
1634: - size - The support size for point p

1636:   Output Parameter:

1638:   Note:
1639:   This should be called after DMPlexSetChart().

1641:   Level: beginner

1643: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1644: @*/
1645: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1646: {
1647:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1654:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1655:   return(0);
1656: }

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

1661:   Not collective

1663:   Input Parameters:
1664: + mesh - The DMPlex
1665: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1670:   Level: beginner

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

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

1678: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1679: @*/
1680: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1681: {
1682:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1683:   PetscInt       off;

1689:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1690:   *support = &mesh->supports[off];
1691:   return(0);
1692: }

1694: /*@
1695:   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG

1697:   Not collective

1699:   Input Parameters:
1700: + mesh - The DMPlex
1701: . p - The point, which must lie in the chart set with DMPlexSetChart()
1702: - support - An array of points which are on the in-edges for point p

1704:   Output Parameter:

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

1709:   Level: beginner

1711: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1712: @*/
1713: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1714: {
1715:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1716:   PetscInt       pStart, pEnd;
1717:   PetscInt       dof, off, c;

1722:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1723:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1725:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1726:   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);
1727:   for (c = 0; c < dof; ++c) {
1728:     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);
1729:     mesh->supports[off+c] = support[c];
1730:   }
1731:   return(0);
1732: }

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

1737:   Not collective

1739:   Input Parameters:
1740: + mesh - The DMPlex
1741: . p - The point, which must lie in the chart set with DMPlexSetChart()
1742: . supportPos - The local index in the cone where the point should be put
1743: - supportPoint - The mesh point to insert

1745:   Level: beginner

1747: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1748: @*/
1749: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1750: {
1751:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1752:   PetscInt       pStart, pEnd;
1753:   PetscInt       dof, off;

1758:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1759:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1760:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1761:   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);
1762:   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);
1763:   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);
1764:   mesh->supports[off+supportPos] = supportPoint;
1765:   return(0);
1766: }

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

1771:   Not collective

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

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

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

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

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

1792:   Level: beginner

1794: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1795: @*/
1796: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1797: {
1798:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1799:   PetscInt       *closure, *fifo;
1800:   const PetscInt *tmp = NULL, *tmpO = NULL;
1801:   PetscInt        tmpSize, t;
1802:   PetscInt        depth       = 0, maxSize;
1803:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1804:   PetscErrorCode  ierr;

1808:   DMPlexGetDepth(dm, &depth);
1809:   /* This is only 1-level */
1810:   if (useCone) {
1811:     DMPlexGetConeSize(dm, p, &tmpSize);
1812:     DMPlexGetCone(dm, p, &tmp);
1813:     DMPlexGetConeOrientation(dm, p, &tmpO);
1814:   } else {
1815:     DMPlexGetSupportSize(dm, p, &tmpSize);
1816:     DMPlexGetSupport(dm, p, &tmp);
1817:   }
1818:   if (depth == 1) {
1819:     if (*points) {
1820:       closure = *points;
1821:     } else {
1822:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1823:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1824:     }
1825:     closure[0] = p; closure[1] = 0;
1826:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1827:       closure[closureSize]   = tmp[t];
1828:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1829:     }
1830:     if (numPoints) *numPoints = closureSize/2;
1831:     if (points)    *points    = closure;
1832:     return(0);
1833:   }
1834:   {
1835:     PetscInt c, coneSeries, s,supportSeries;

1837:     c = mesh->maxConeSize;
1838:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1839:     s = mesh->maxSupportSize;
1840:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1841:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1842:   }
1843:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
1844:   if (*points) {
1845:     closure = *points;
1846:   } else {
1847:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1848:   }
1849:   closure[0] = p; closure[1] = 0;
1850:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1851:     const PetscInt cp = tmp[t];
1852:     const PetscInt co = tmpO ? tmpO[t] : 0;

1854:     closure[closureSize]   = cp;
1855:     closure[closureSize+1] = co;
1856:     fifo[fifoSize]         = cp;
1857:     fifo[fifoSize+1]       = co;
1858:   }
1859:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1860:   while (fifoSize - fifoStart) {
1861:     const PetscInt q   = fifo[fifoStart];
1862:     const PetscInt o   = fifo[fifoStart+1];
1863:     const PetscInt rev = o >= 0 ? 0 : 1;
1864:     const PetscInt off = rev ? -(o+1) : o;

1866:     if (useCone) {
1867:       DMPlexGetConeSize(dm, q, &tmpSize);
1868:       DMPlexGetCone(dm, q, &tmp);
1869:       DMPlexGetConeOrientation(dm, q, &tmpO);
1870:     } else {
1871:       DMPlexGetSupportSize(dm, q, &tmpSize);
1872:       DMPlexGetSupport(dm, q, &tmp);
1873:       tmpO = NULL;
1874:     }
1875:     for (t = 0; t < tmpSize; ++t) {
1876:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1877:       const PetscInt cp = tmp[i];
1878:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1879:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1880:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1881:       PetscInt       co = tmpO ? tmpO[i] : 0;
1882:       PetscInt       c;

1884:       if (rev) {
1885:         PetscInt childSize, coff;
1886:         DMPlexGetConeSize(dm, cp, &childSize);
1887:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1888:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1889:       }
1890:       /* Check for duplicate */
1891:       for (c = 0; c < closureSize; c += 2) {
1892:         if (closure[c] == cp) break;
1893:       }
1894:       if (c == closureSize) {
1895:         closure[closureSize]   = cp;
1896:         closure[closureSize+1] = co;
1897:         fifo[fifoSize]         = cp;
1898:         fifo[fifoSize+1]       = co;
1899:         closureSize           += 2;
1900:         fifoSize              += 2;
1901:       }
1902:     }
1903:     fifoStart += 2;
1904:   }
1905:   if (numPoints) *numPoints = closureSize/2;
1906:   if (points)    *points    = closure;
1907:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
1908:   return(0);
1909: }

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

1914:   Not collective

1916:   Input Parameters:
1917: + mesh - The DMPlex
1918: . p - The point, which must lie in the chart set with DMPlexSetChart()
1919: . orientation - The orientation of the point
1920: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1921: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

1936:   Level: beginner

1938: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1939: @*/
1940: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1941: {
1942:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1943:   PetscInt       *closure, *fifo;
1944:   const PetscInt *tmp = NULL, *tmpO = NULL;
1945:   PetscInt        tmpSize, t;
1946:   PetscInt        depth       = 0, maxSize;
1947:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1948:   PetscErrorCode  ierr;

1952:   DMPlexGetDepth(dm, &depth);
1953:   /* This is only 1-level */
1954:   if (useCone) {
1955:     DMPlexGetConeSize(dm, p, &tmpSize);
1956:     DMPlexGetCone(dm, p, &tmp);
1957:     DMPlexGetConeOrientation(dm, p, &tmpO);
1958:   } else {
1959:     DMPlexGetSupportSize(dm, p, &tmpSize);
1960:     DMPlexGetSupport(dm, p, &tmp);
1961:   }
1962:   if (depth == 1) {
1963:     if (*points) {
1964:       closure = *points;
1965:     } else {
1966:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1967:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1968:     }
1969:     closure[0] = p; closure[1] = ornt;
1970:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1971:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1972:       closure[closureSize]   = tmp[i];
1973:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1974:     }
1975:     if (numPoints) *numPoints = closureSize/2;
1976:     if (points)    *points    = closure;
1977:     return(0);
1978:   }
1979:   {
1980:     PetscInt c, coneSeries, s,supportSeries;

1982:     c = mesh->maxConeSize;
1983:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1984:     s = mesh->maxSupportSize;
1985:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1986:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1987:   }
1988:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
1989:   if (*points) {
1990:     closure = *points;
1991:   } else {
1992:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1993:   }
1994:   closure[0] = p; closure[1] = ornt;
1995:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1996:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1997:     const PetscInt cp = tmp[i];
1998:     PetscInt       co = tmpO ? tmpO[i] : 0;

2000:     if (ornt < 0) {
2001:       PetscInt childSize, coff;
2002:       DMPlexGetConeSize(dm, cp, &childSize);
2003:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2004:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2005:     }
2006:     closure[closureSize]   = cp;
2007:     closure[closureSize+1] = co;
2008:     fifo[fifoSize]         = cp;
2009:     fifo[fifoSize+1]       = co;
2010:   }
2011:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2012:   while (fifoSize - fifoStart) {
2013:     const PetscInt q   = fifo[fifoStart];
2014:     const PetscInt o   = fifo[fifoStart+1];
2015:     const PetscInt rev = o >= 0 ? 0 : 1;
2016:     const PetscInt off = rev ? -(o+1) : o;

2018:     if (useCone) {
2019:       DMPlexGetConeSize(dm, q, &tmpSize);
2020:       DMPlexGetCone(dm, q, &tmp);
2021:       DMPlexGetConeOrientation(dm, q, &tmpO);
2022:     } else {
2023:       DMPlexGetSupportSize(dm, q, &tmpSize);
2024:       DMPlexGetSupport(dm, q, &tmp);
2025:       tmpO = NULL;
2026:     }
2027:     for (t = 0; t < tmpSize; ++t) {
2028:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2029:       const PetscInt cp = tmp[i];
2030:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2031:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2032:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2033:       PetscInt       co = tmpO ? tmpO[i] : 0;
2034:       PetscInt       c;

2036:       if (rev) {
2037:         PetscInt childSize, coff;
2038:         DMPlexGetConeSize(dm, cp, &childSize);
2039:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2040:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2041:       }
2042:       /* Check for duplicate */
2043:       for (c = 0; c < closureSize; c += 2) {
2044:         if (closure[c] == cp) break;
2045:       }
2046:       if (c == closureSize) {
2047:         closure[closureSize]   = cp;
2048:         closure[closureSize+1] = co;
2049:         fifo[fifoSize]         = cp;
2050:         fifo[fifoSize+1]       = co;
2051:         closureSize           += 2;
2052:         fifoSize              += 2;
2053:       }
2054:     }
2055:     fifoStart += 2;
2056:   }
2057:   if (numPoints) *numPoints = closureSize/2;
2058:   if (points)    *points    = closure;
2059:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2060:   return(0);
2061: }

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

2066:   Not collective

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

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

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

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

2084:   Level: beginner

2086: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2087: @*/
2088: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2089: {

2096:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2097:   if (numPoints) *numPoints = 0;
2098:   return(0);
2099: }

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

2104:   Not collective

2106:   Input Parameter:
2107: . mesh - The DMPlex

2109:   Output Parameters:
2110: + maxConeSize - The maximum number of in-edges
2111: - maxSupportSize - The maximum number of out-edges

2113:   Level: beginner

2115: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2116: @*/
2117: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2118: {
2119:   DM_Plex *mesh = (DM_Plex*) dm->data;

2123:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2124:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2125:   return(0);
2126: }

2128: PetscErrorCode DMSetUp_Plex(DM dm)
2129: {
2130:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2131:   PetscInt       size;

2136:   PetscSectionSetUp(mesh->coneSection);
2137:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2138:   PetscMalloc1(size, &mesh->cones);
2139:   PetscCalloc1(size, &mesh->coneOrientations);
2140:   if (mesh->maxSupportSize) {
2141:     PetscSectionSetUp(mesh->supportSection);
2142:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2143:     PetscMalloc1(size, &mesh->supports);
2144:   }
2145:   return(0);
2146: }

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

2153:   if (subdm) {DMClone(dm, subdm);}
2154:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2155:   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2156:   if (dm->useNatural && dm->sfMigration) {
2157:     PetscSF        sfMigrationInv,sfNatural;
2158:     PetscSection   section, sectionSeq;

2160:     (*subdm)->sfMigration = dm->sfMigration;
2161:     PetscObjectReference((PetscObject) dm->sfMigration);
2162:     DMGetDefaultSection((*subdm), &section);
2163:     PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);
2164:     PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);
2165:     PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2166: 
2167:     DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);
2168:     (*subdm)->sfNatural = sfNatural;
2169:     PetscSectionDestroy(&sectionSeq);
2170:     PetscSFDestroy(&sfMigrationInv);
2171:   }
2172:   return(0);
2173: }

2175: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2176: {
2178:   PetscInt       i = 0;

2181:   if (superdm) {DMClone(dms[0], superdm);}
2182:   DMCreateSuperDM_Section_Private(dms, len, is, superdm);
2183:   (*superdm)->useNatural = PETSC_FALSE;
2184:   for (i = 0; i < len; i++){
2185:     if (dms[i]->useNatural && dms[i]->sfMigration) {
2186:       PetscSF        sfMigrationInv,sfNatural;
2187:       PetscSection   section, sectionSeq;

2189:       (*superdm)->sfMigration = dms[i]->sfMigration;
2190:       PetscObjectReference((PetscObject) dms[i]->sfMigration);
2191:       (*superdm)->useNatural = PETSC_TRUE;
2192:       DMGetDefaultSection((*superdm), &section);
2193:       PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);
2194:       PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);
2195:       PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);
2196: 
2197:       DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);
2198:       (*superdm)->sfNatural = sfNatural;
2199:       PetscSectionDestroy(&sectionSeq);
2200:       PetscSFDestroy(&sfMigrationInv);
2201:       break;
2202:     }
2203:   }
2204:   return(0);
2205: }

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

2210:   Not collective

2212:   Input Parameter:
2213: . mesh - The DMPlex

2215:   Output Parameter:

2217:   Note:
2218:   This should be called after all calls to DMPlexSetCone()

2220:   Level: beginner

2222: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2223: @*/
2224: PetscErrorCode DMPlexSymmetrize(DM dm)
2225: {
2226:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2227:   PetscInt      *offsets;
2228:   PetscInt       supportSize;
2229:   PetscInt       pStart, pEnd, p;

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

2240:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2241:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2242:     for (c = off; c < off+dof; ++c) {
2243:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2244:     }
2245:   }
2246:   for (p = pStart; p < pEnd; ++p) {
2247:     PetscInt dof;

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

2251:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2252:   }
2253:   PetscSectionSetUp(mesh->supportSection);
2254:   /* Calculate supports */
2255:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2256:   PetscMalloc1(supportSize, &mesh->supports);
2257:   PetscCalloc1(pEnd - pStart, &offsets);
2258:   for (p = pStart; p < pEnd; ++p) {
2259:     PetscInt dof, off, c;

2261:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2262:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2263:     for (c = off; c < off+dof; ++c) {
2264:       const PetscInt q = mesh->cones[c];
2265:       PetscInt       offS;

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

2269:       mesh->supports[offS+offsets[q]] = p;
2270:       ++offsets[q];
2271:     }
2272:   }
2273:   PetscFree(offsets);
2274:   return(0);
2275: }

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

2283:   Collective on dm

2285:   Input Parameter:
2286: . mesh - The DMPlex

2288:   Output Parameter:

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

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

2298:   Level: beginner

2300: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2301: @*/
2302: PetscErrorCode DMPlexStratify(DM dm)
2303: {
2304:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2305:   DMLabel        label;
2306:   PetscInt       pStart, pEnd, p;
2307:   PetscInt       numRoots = 0, numLeaves = 0;

2312:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2313:   /* Calculate depth */
2314:   DMPlexGetChart(dm, &pStart, &pEnd);
2315:   DMCreateLabel(dm, "depth");
2316:   DMPlexGetDepthLabel(dm, &label);
2317:   /* Initialize roots and count leaves */
2318:   for (p = pStart; p < pEnd; ++p) {
2319:     PetscInt coneSize, supportSize;

2321:     DMPlexGetConeSize(dm, p, &coneSize);
2322:     DMPlexGetSupportSize(dm, p, &supportSize);
2323:     if (!coneSize && supportSize) {
2324:       ++numRoots;
2325:       DMLabelSetValue(label, p, 0);
2326:     } else if (!supportSize && coneSize) {
2327:       ++numLeaves;
2328:     } else if (!supportSize && !coneSize) {
2329:       /* Isolated points */
2330:       DMLabelSetValue(label, p, 0);
2331:     }
2332:   }
2333:   if (numRoots + numLeaves == (pEnd - pStart)) {
2334:     for (p = pStart; p < pEnd; ++p) {
2335:       PetscInt coneSize, supportSize;

2337:       DMPlexGetConeSize(dm, p, &coneSize);
2338:       DMPlexGetSupportSize(dm, p, &supportSize);
2339:       if (!supportSize && coneSize) {
2340:         DMLabelSetValue(label, p, 1);
2341:       }
2342:     }
2343:   } else {
2344:     IS       pointIS;
2345:     PetscInt numPoints = 0, level = 0;

2347:     DMLabelGetStratumIS(label, level, &pointIS);
2348:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2349:     while (numPoints) {
2350:       const PetscInt *points;
2351:       const PetscInt  newLevel = level+1;

2353:       ISGetIndices(pointIS, &points);
2354:       for (p = 0; p < numPoints; ++p) {
2355:         const PetscInt  point = points[p];
2356:         const PetscInt *support;
2357:         PetscInt        supportSize, s;

2359:         DMPlexGetSupportSize(dm, point, &supportSize);
2360:         DMPlexGetSupport(dm, point, &support);
2361:         for (s = 0; s < supportSize; ++s) {
2362:           DMLabelSetValue(label, support[s], newLevel);
2363:         }
2364:       }
2365:       ISRestoreIndices(pointIS, &points);
2366:       ++level;
2367:       ISDestroy(&pointIS);
2368:       DMLabelGetStratumIS(label, level, &pointIS);
2369:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2370:       else         {numPoints = 0;}
2371:     }
2372:     ISDestroy(&pointIS);
2373:   }
2374:   { /* just in case there is an empty process */
2375:     PetscInt numValues, maxValues = 0, v;

2377:     DMLabelGetNumValues(label,&numValues);
2378:     for (v = 0; v < numValues; v++) {
2379:       IS pointIS;

2381:       DMLabelGetStratumIS(label, v, &pointIS);
2382:       if (pointIS) {
2383:         PetscInt  min, max, numPoints;
2384:         PetscInt  start;
2385:         PetscBool contig;

2387:         ISGetLocalSize(pointIS, &numPoints);
2388:         ISGetMinMax(pointIS, &min, &max);
2389:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2390:         if (start == 0 && contig) {
2391:           ISDestroy(&pointIS);
2392:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2393:           DMLabelSetStratumIS(label, v, pointIS);
2394:         }
2395:       }
2396:       ISDestroy(&pointIS);
2397:     }
2398:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2399:     for (v = numValues; v < maxValues; v++) {
2400:       DMLabelAddStratum(label,v);
2401:     }
2402:   }

2404:   DMLabelGetState(label, &mesh->depthState);
2405:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2406:   return(0);
2407: }

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

2412:   Not Collective

2414:   Input Parameters:
2415: + dm - The DMPlex object
2416: . numPoints - The number of input points for the join
2417: - points - The input points

2419:   Output Parameters:
2420: + numCoveredPoints - The number of points in the join
2421: - coveredPoints - The points in the join

2423:   Level: intermediate

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

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

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

2433: .keywords: mesh
2434: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2435: @*/
2436: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2437: {
2438:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2439:   PetscInt      *join[2];
2440:   PetscInt       joinSize, i = 0;
2441:   PetscInt       dof, off, p, c, m;

2449:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2450:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2451:   /* Copy in support of first point */
2452:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2453:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2454:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2455:     join[i][joinSize] = mesh->supports[off+joinSize];
2456:   }
2457:   /* Check each successive support */
2458:   for (p = 1; p < numPoints; ++p) {
2459:     PetscInt newJoinSize = 0;

2461:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2462:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2463:     for (c = 0; c < dof; ++c) {
2464:       const PetscInt point = mesh->supports[off+c];

2466:       for (m = 0; m < joinSize; ++m) {
2467:         if (point == join[i][m]) {
2468:           join[1-i][newJoinSize++] = point;
2469:           break;
2470:         }
2471:       }
2472:     }
2473:     joinSize = newJoinSize;
2474:     i        = 1-i;
2475:   }
2476:   *numCoveredPoints = joinSize;
2477:   *coveredPoints    = join[i];
2478:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2479:   return(0);
2480: }

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

2485:   Not Collective

2487:   Input Parameters:
2488: + dm - The DMPlex object
2489: . numPoints - The number of input points for the join
2490: - points - The input points

2492:   Output Parameters:
2493: + numCoveredPoints - The number of points in the join
2494: - coveredPoints - The points in the join

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

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

2502:   Level: intermediate

2504: .keywords: mesh
2505: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2506: @*/
2507: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2508: {

2516:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2517:   if (numCoveredPoints) *numCoveredPoints = 0;
2518:   return(0);
2519: }

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

2524:   Not Collective

2526:   Input Parameters:
2527: + dm - The DMPlex object
2528: . numPoints - The number of input points for the join
2529: - points - The input points

2531:   Output Parameters:
2532: + numCoveredPoints - The number of points in the join
2533: - coveredPoints - The points in the join

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

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

2541:   Level: intermediate

2543: .keywords: mesh
2544: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2545: @*/
2546: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2547: {
2548:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2549:   PetscInt      *offsets, **closures;
2550:   PetscInt      *join[2];
2551:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2552:   PetscInt       p, d, c, m, ms;


2561:   DMPlexGetDepth(dm, &depth);
2562:   PetscCalloc1(numPoints, &closures);
2563:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2564:   ms      = mesh->maxSupportSize;
2565:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2566:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2567:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

2569:   for (p = 0; p < numPoints; ++p) {
2570:     PetscInt closureSize;

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

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

2578:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2579:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2580:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2581:           offsets[p*(depth+2)+d+1] = i;
2582:           break;
2583:         }
2584:       }
2585:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2586:     }
2587:     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);
2588:   }
2589:   for (d = 0; d < depth+1; ++d) {
2590:     PetscInt dof;

2592:     /* Copy in support of first point */
2593:     dof = offsets[d+1] - offsets[d];
2594:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2595:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2596:     }
2597:     /* Check each successive cone */
2598:     for (p = 1; p < numPoints && joinSize; ++p) {
2599:       PetscInt newJoinSize = 0;

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

2605:         for (m = 0; m < joinSize; ++m) {
2606:           if (point == join[i][m]) {
2607:             join[1-i][newJoinSize++] = point;
2608:             break;
2609:           }
2610:         }
2611:       }
2612:       joinSize = newJoinSize;
2613:       i        = 1-i;
2614:     }
2615:     if (joinSize) break;
2616:   }
2617:   *numCoveredPoints = joinSize;
2618:   *coveredPoints    = join[i];
2619:   for (p = 0; p < numPoints; ++p) {
2620:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2621:   }
2622:   PetscFree(closures);
2623:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2624:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2625:   return(0);
2626: }

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

2631:   Not Collective

2633:   Input Parameters:
2634: + dm - The DMPlex object
2635: . numPoints - The number of input points for the meet
2636: - points - The input points

2638:   Output Parameters:
2639: + numCoveredPoints - The number of points in the meet
2640: - coveredPoints - The points in the meet

2642:   Level: intermediate

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

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

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

2652: .keywords: mesh
2653: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2654: @*/
2655: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2656: {
2657:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2658:   PetscInt      *meet[2];
2659:   PetscInt       meetSize, i = 0;
2660:   PetscInt       dof, off, p, c, m;

2668:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
2669:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
2670:   /* Copy in cone of first point */
2671:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2672:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2673:   for (meetSize = 0; meetSize < dof; ++meetSize) {
2674:     meet[i][meetSize] = mesh->cones[off+meetSize];
2675:   }
2676:   /* Check each successive cone */
2677:   for (p = 1; p < numPoints; ++p) {
2678:     PetscInt newMeetSize = 0;

2680:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2681:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2682:     for (c = 0; c < dof; ++c) {
2683:       const PetscInt point = mesh->cones[off+c];

2685:       for (m = 0; m < meetSize; ++m) {
2686:         if (point == meet[i][m]) {
2687:           meet[1-i][newMeetSize++] = point;
2688:           break;
2689:         }
2690:       }
2691:     }
2692:     meetSize = newMeetSize;
2693:     i        = 1-i;
2694:   }
2695:   *numCoveringPoints = meetSize;
2696:   *coveringPoints    = meet[i];
2697:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2698:   return(0);
2699: }

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

2704:   Not Collective

2706:   Input Parameters:
2707: + dm - The DMPlex object
2708: . numPoints - The number of input points for the meet
2709: - points - The input points

2711:   Output Parameters:
2712: + numCoveredPoints - The number of points in the meet
2713: - coveredPoints - The points in the meet

2715:   Level: intermediate

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

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

2723: .keywords: mesh
2724: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2725: @*/
2726: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2727: {

2735:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2736:   if (numCoveredPoints) *numCoveredPoints = 0;
2737:   return(0);
2738: }

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

2743:   Not Collective

2745:   Input Parameters:
2746: + dm - The DMPlex object
2747: . numPoints - The number of input points for the meet
2748: - points - The input points

2750:   Output Parameters:
2751: + numCoveredPoints - The number of points in the meet
2752: - coveredPoints - The points in the meet

2754:   Level: intermediate

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

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

2762: .keywords: mesh
2763: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2764: @*/
2765: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2766: {
2767:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2768:   PetscInt      *offsets, **closures;
2769:   PetscInt      *meet[2];
2770:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2771:   PetscInt       p, h, c, m, mc;


2780:   DMPlexGetDepth(dm, &height);
2781:   PetscMalloc1(numPoints, &closures);
2782:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2783:   mc      = mesh->maxConeSize;
2784:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2785:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
2786:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

2788:   for (p = 0; p < numPoints; ++p) {
2789:     PetscInt closureSize;

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

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

2797:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2798:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2799:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2800:           offsets[p*(height+2)+h+1] = i;
2801:           break;
2802:         }
2803:       }
2804:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2805:     }
2806:     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);
2807:   }
2808:   for (h = 0; h < height+1; ++h) {
2809:     PetscInt dof;

2811:     /* Copy in cone of first point */
2812:     dof = offsets[h+1] - offsets[h];
2813:     for (meetSize = 0; meetSize < dof; ++meetSize) {
2814:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2815:     }
2816:     /* Check each successive cone */
2817:     for (p = 1; p < numPoints && meetSize; ++p) {
2818:       PetscInt newMeetSize = 0;

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

2824:         for (m = 0; m < meetSize; ++m) {
2825:           if (point == meet[i][m]) {
2826:             meet[1-i][newMeetSize++] = point;
2827:             break;
2828:           }
2829:         }
2830:       }
2831:       meetSize = newMeetSize;
2832:       i        = 1-i;
2833:     }
2834:     if (meetSize) break;
2835:   }
2836:   *numCoveredPoints = meetSize;
2837:   *coveredPoints    = meet[i];
2838:   for (p = 0; p < numPoints; ++p) {
2839:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2840:   }
2841:   PetscFree(closures);
2842:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2843:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2844:   return(0);
2845: }

2847: /*@C
2848:   DMPlexEqual - Determine if two DMs have the same topology

2850:   Not Collective

2852:   Input Parameters:
2853: + dmA - A DMPlex object
2854: - dmB - A DMPlex object

2856:   Output Parameters:
2857: . equal - PETSC_TRUE if the topologies are identical

2859:   Level: intermediate

2861:   Notes:
2862:   We are not solving graph isomorphism, so we do not permutation.

2864: .keywords: mesh
2865: .seealso: DMPlexGetCone()
2866: @*/
2867: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2868: {
2869:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


2877:   *equal = PETSC_FALSE;
2878:   DMPlexGetDepth(dmA, &depth);
2879:   DMPlexGetDepth(dmB, &depthB);
2880:   if (depth != depthB) return(0);
2881:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2882:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2883:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2884:   for (p = pStart; p < pEnd; ++p) {
2885:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2886:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

2888:     DMPlexGetConeSize(dmA, p, &coneSize);
2889:     DMPlexGetCone(dmA, p, &cone);
2890:     DMPlexGetConeOrientation(dmA, p, &ornt);
2891:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2892:     DMPlexGetCone(dmB, p, &coneB);
2893:     DMPlexGetConeOrientation(dmB, p, &orntB);
2894:     if (coneSize != coneSizeB) return(0);
2895:     for (c = 0; c < coneSize; ++c) {
2896:       if (cone[c] != coneB[c]) return(0);
2897:       if (ornt[c] != orntB[c]) return(0);
2898:     }
2899:     DMPlexGetSupportSize(dmA, p, &supportSize);
2900:     DMPlexGetSupport(dmA, p, &support);
2901:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2902:     DMPlexGetSupport(dmB, p, &supportB);
2903:     if (supportSize != supportSizeB) return(0);
2904:     for (s = 0; s < supportSize; ++s) {
2905:       if (support[s] != supportB[s]) return(0);
2906:     }
2907:   }
2908:   *equal = PETSC_TRUE;
2909:   return(0);
2910: }

2912: /*@C
2913:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

2915:   Not Collective

2917:   Input Parameters:
2918: + dm         - The DMPlex
2919: . cellDim    - The cell dimension
2920: - numCorners - The number of vertices on a cell

2922:   Output Parameters:
2923: . numFaceVertices - The number of vertices on a face

2925:   Level: developer

2927:   Notes:
2928:   Of course this can only work for a restricted set of symmetric shapes

2930: .seealso: DMPlexGetCone()
2931: @*/
2932: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2933: {
2934:   MPI_Comm       comm;

2938:   PetscObjectGetComm((PetscObject)dm,&comm);
2940:   switch (cellDim) {
2941:   case 0:
2942:     *numFaceVertices = 0;
2943:     break;
2944:   case 1:
2945:     *numFaceVertices = 1;
2946:     break;
2947:   case 2:
2948:     switch (numCorners) {
2949:     case 3: /* triangle */
2950:       *numFaceVertices = 2; /* Edge has 2 vertices */
2951:       break;
2952:     case 4: /* quadrilateral */
2953:       *numFaceVertices = 2; /* Edge has 2 vertices */
2954:       break;
2955:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2956:       *numFaceVertices = 3; /* Edge has 3 vertices */
2957:       break;
2958:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2959:       *numFaceVertices = 3; /* Edge has 3 vertices */
2960:       break;
2961:     default:
2962:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2963:     }
2964:     break;
2965:   case 3:
2966:     switch (numCorners) {
2967:     case 4: /* tetradehdron */
2968:       *numFaceVertices = 3; /* Face has 3 vertices */
2969:       break;
2970:     case 6: /* tet cohesive cells */
2971:       *numFaceVertices = 4; /* Face has 4 vertices */
2972:       break;
2973:     case 8: /* hexahedron */
2974:       *numFaceVertices = 4; /* Face has 4 vertices */
2975:       break;
2976:     case 9: /* tet cohesive Lagrange cells */
2977:       *numFaceVertices = 6; /* Face has 6 vertices */
2978:       break;
2979:     case 10: /* quadratic tetrahedron */
2980:       *numFaceVertices = 6; /* Face has 6 vertices */
2981:       break;
2982:     case 12: /* hex cohesive Lagrange cells */
2983:       *numFaceVertices = 6; /* Face has 6 vertices */
2984:       break;
2985:     case 18: /* quadratic tet cohesive Lagrange cells */
2986:       *numFaceVertices = 6; /* Face has 6 vertices */
2987:       break;
2988:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2989:       *numFaceVertices = 9; /* Face has 9 vertices */
2990:       break;
2991:     default:
2992:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2993:     }
2994:     break;
2995:   default:
2996:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
2997:   }
2998:   return(0);
2999: }

3001: /*@
3002:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

3004:   Not Collective

3006:   Input Parameter:
3007: . dm    - The DMPlex object

3009:   Output Parameter:
3010: . depthLabel - The DMLabel recording point depth

3012:   Level: developer

3014: .keywords: mesh, points
3015: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3016: @*/
3017: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3018: {

3024:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
3025:   *depthLabel = dm->depthLabel;
3026:   return(0);
3027: }

3029: /*@
3030:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

3032:   Not Collective

3034:   Input Parameter:
3035: . dm    - The DMPlex object

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

3040:   Level: developer

3042: .keywords: mesh, points
3043: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3044: @*/
3045: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3046: {
3047:   DMLabel        label;
3048:   PetscInt       d = 0;

3054:   DMPlexGetDepthLabel(dm, &label);
3055:   if (label) {DMLabelGetNumValues(label, &d);}
3056:   *depth = d-1;
3057:   return(0);
3058: }

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

3063:   Not Collective

3065:   Input Parameters:
3066: + dm           - The DMPlex object
3067: - stratumValue - The requested depth

3069:   Output Parameters:
3070: + start - The first point at this depth
3071: - end   - One beyond the last point at this depth

3073:   Level: developer

3075: .keywords: mesh, points
3076: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3077: @*/
3078: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3079: {
3080:   DMLabel        label;
3081:   PetscInt       pStart, pEnd;

3088:   DMPlexGetChart(dm, &pStart, &pEnd);
3089:   if (pStart == pEnd) return(0);
3090:   if (stratumValue < 0) {
3091:     if (start) *start = pStart;
3092:     if (end)   *end   = pEnd;
3093:     return(0);
3094:   }
3095:   DMPlexGetDepthLabel(dm, &label);
3096:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3097:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3098:   return(0);
3099: }

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

3104:   Not Collective

3106:   Input Parameters:
3107: + dm           - The DMPlex object
3108: - stratumValue - The requested height

3110:   Output Parameters:
3111: + start - The first point at this height
3112: - end   - One beyond the last point at this height

3114:   Level: developer

3116: .keywords: mesh, points
3117: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3118: @*/
3119: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3120: {
3121:   DMLabel        label;
3122:   PetscInt       depth, pStart, pEnd;

3129:   DMPlexGetChart(dm, &pStart, &pEnd);
3130:   if (pStart == pEnd) return(0);
3131:   if (stratumValue < 0) {
3132:     if (start) *start = pStart;
3133:     if (end)   *end   = pEnd;
3134:     return(0);
3135:   }
3136:   DMPlexGetDepthLabel(dm, &label);
3137:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3138:   DMLabelGetNumValues(label, &depth);
3139:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3140:   return(0);
3141: }

3143: /* Set the number of dof on each point and separate by fields */
3144: static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3145: {
3146:   PetscInt      *pMax;
3147:   PetscInt       depth, cellHeight, pStart = 0, pEnd = 0;
3148:   PetscInt       Nf, p, d, dep, f;
3149:   PetscBool     *isFE;

3153:   PetscMalloc1(numFields, &isFE);
3154:   DMGetNumFields(dm, &Nf);
3155:   for (f = 0; f < numFields; ++f) {
3156:     PetscObject  obj;
3157:     PetscClassId id;

3159:     isFE[f] = PETSC_FALSE;
3160:     if (f >= Nf) continue;
3161:     DMGetField(dm, f, &obj);
3162:     PetscObjectGetClassId(obj, &id);
3163:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
3164:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3165:   }
3166:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
3167:   if (numFields > 0) {
3168:     PetscSectionSetNumFields(*section, numFields);
3169:     if (numComp) {
3170:       for (f = 0; f < numFields; ++f) {
3171:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
3172:         if (isFE[f]) {
3173:           PetscFE           fe;
3174:           PetscDualSpace    dspace;
3175:           const PetscInt    ***perms;
3176:           const PetscScalar ***flips;
3177:           const PetscInt    *numDof;

3179:           DMGetField(dm,f,(PetscObject *) &fe);
3180:           PetscFEGetDualSpace(fe,&dspace);
3181:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3182:           PetscDualSpaceGetNumDof(dspace,&numDof);
3183:           if (perms || flips) {
3184:             DM               K;
3185:             DMLabel          depthLabel;
3186:             PetscInt         depth, h;
3187:             PetscSectionSym  sym;

3189:             PetscDualSpaceGetDM(dspace,&K);
3190:             DMPlexGetDepthLabel(dm,&depthLabel);
3191:             DMPlexGetDepth(dm,&depth);
3192:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
3193:             for (h = 0; h <= depth; h++) {
3194:               PetscDualSpace    hspace;
3195:               PetscInt          kStart, kEnd;
3196:               PetscInt          kConeSize;
3197:               const PetscInt    **perms0 = NULL;
3198:               const PetscScalar **flips0 = NULL;

3200:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
3201:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
3202:               if (!hspace) continue;
3203:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
3204:               if (perms) perms0 = perms[0];
3205:               if (flips) flips0 = flips[0];
3206:               if (!(perms0 || flips0)) continue;
3207:               DMPlexGetConeSize(K,kStart,&kConeSize);
3208:               PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
3209:             }
3210:             PetscSectionSetFieldSym(*section,f,sym);
3211:             PetscSectionSymDestroy(&sym);
3212:           }
3213:         }
3214:       }
3215:     }
3216:   }
3217:   DMPlexGetChart(dm, &pStart, &pEnd);
3218:   PetscSectionSetChart(*section, pStart, pEnd);
3219:   DMPlexGetDepth(dm, &depth);
3220:   PetscMalloc1(depth+1,&pMax);
3221:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3222:   DMPlexGetVTKCellHeight(dm, &cellHeight);
3223:   for (dep = 0; dep <= depth - cellHeight; ++dep) {
3224:     d    = dim == depth ? dep : (!dep ? 0 : dim);
3225:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3226:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3227:     for (p = pStart; p < pEnd; ++p) {
3228:       PetscInt tot = 0;

3230:       for (f = 0; f < numFields; ++f) {
3231:         if (isFE[f] && p >= pMax[dep]) continue;
3232:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3233:         tot += numDof[f*(dim+1)+d];
3234:       }
3235:       PetscSectionSetDof(*section, p, tot);
3236:     }
3237:   }
3238:   PetscFree(pMax);
3239:   PetscFree(isFE);
3240:   return(0);
3241: }

3243: /* Set the number of dof on each point and separate by fields
3244:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3245: */
3246: static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3247: {
3248:   PetscInt       numFields;
3249:   PetscInt       bc;
3250:   PetscSection   aSec;

3254:   PetscSectionGetNumFields(section, &numFields);
3255:   for (bc = 0; bc < numBC; ++bc) {
3256:     PetscInt        field = 0;
3257:     const PetscInt *comp;
3258:     const PetscInt *idx;
3259:     PetscInt        Nc = -1, n, i;

3261:     if (numFields) field = bcField[bc];
3262:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3263:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3264:     ISGetLocalSize(bcPoints[bc], &n);
3265:     ISGetIndices(bcPoints[bc], &idx);
3266:     for (i = 0; i < n; ++i) {
3267:       const PetscInt p = idx[i];
3268:       PetscInt       numConst;

3270:       if (numFields) {
3271:         PetscSectionGetFieldDof(section, p, field, &numConst);
3272:       } else {
3273:         PetscSectionGetDof(section, p, &numConst);
3274:       }
3275:       /* If Nc < 0, constrain every dof on the point */
3276:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3277:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3278:       PetscSectionAddConstraintDof(section, p, numConst);
3279:     }
3280:     ISRestoreIndices(bcPoints[bc], &idx);
3281:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3282:   }
3283:   DMPlexGetAnchors(dm, &aSec, NULL);
3284:   if (aSec) {
3285:     PetscInt aStart, aEnd, a;

3287:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3288:     for (a = aStart; a < aEnd; a++) {
3289:       PetscInt dof, f;

3291:       PetscSectionGetDof(aSec, a, &dof);
3292:       if (dof) {
3293:         /* if there are point-to-point constraints, then all dofs are constrained */
3294:         PetscSectionGetDof(section, a, &dof);
3295:         PetscSectionSetConstraintDof(section, a, dof);
3296:         for (f = 0; f < numFields; f++) {
3297:           PetscSectionGetFieldDof(section, a, f, &dof);
3298:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3299:         }
3300:       }
3301:     }
3302:   }
3303:   return(0);
3304: }

3306: /* Set the constrained field indices on each point
3307:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3308: */
3309: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3310: {
3311:   PetscSection   aSec;
3312:   PetscInt      *indices;
3313:   PetscInt       numFields, cdof, maxDof = 0, pStart, pEnd, p, bc, f, d;

3317:   PetscSectionGetNumFields(section, &numFields);
3318:   if (!numFields) return(0);
3319:   /* Initialize all field indices to -1 */
3320:   PetscSectionGetChart(section, &pStart, &pEnd);
3321:   for (p = pStart; p < pEnd; ++p) {PetscSectionGetConstraintDof(section, p, &cdof); maxDof = PetscMax(maxDof, cdof);}
3322:   PetscMalloc1(maxDof, &indices);
3323:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3324:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3325:   /* Handle BC constraints */
3326:   for (bc = 0; bc < numBC; ++bc) {
3327:     const PetscInt  field = bcField[bc];
3328:     const PetscInt *comp, *idx;
3329:     PetscInt        Nc = -1, n, i;

3331:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3332:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3333:     ISGetLocalSize(bcPoints[bc], &n);
3334:     ISGetIndices(bcPoints[bc], &idx);
3335:     for (i = 0; i < n; ++i) {
3336:       const PetscInt  p = idx[i];
3337:       const PetscInt *find;
3338:       PetscInt        fdof, fcdof, c;

3340:       PetscSectionGetFieldDof(section, p, field, &fdof);
3341:       if (!fdof) continue;
3342:       if (Nc < 0) {
3343:         for (d = 0; d < fdof; ++d) indices[d] = d;
3344:         fcdof = fdof;
3345:       } else {
3346:         PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3347:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3348:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3349:         for (c = 0; c < Nc; ++c) indices[d++] = comp[c];
3350:         PetscSortRemoveDupsInt(&d, indices);
3351:         for (c = d; c < fcdof; ++c) indices[c] = -1;
3352:         fcdof = d;
3353:       }
3354:       PetscSectionSetFieldConstraintDof(section, p, field, fcdof);
3355:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3356:     }
3357:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3358:     ISRestoreIndices(bcPoints[bc], &idx);
3359:   }
3360:   /* Handle anchors */
3361:   DMPlexGetAnchors(dm, &aSec, NULL);
3362:   if (aSec) {
3363:     PetscInt aStart, aEnd, a;

3365:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3366:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3367:     for (a = aStart; a < aEnd; a++) {
3368:       PetscInt dof, f;

3370:       PetscSectionGetDof(aSec, a, &dof);
3371:       if (dof) {
3372:         /* if there are point-to-point constraints, then all dofs are constrained */
3373:         for (f = 0; f < numFields; f++) {
3374:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3375:         }
3376:       }
3377:     }
3378:   }
3379:   PetscFree(indices);
3380:   return(0);
3381: }

3383: /* Set the constrained indices on each point */
3384: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3385: {
3386:   PetscInt      *indices;
3387:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3391:   PetscSectionGetNumFields(section, &numFields);
3392:   PetscSectionGetMaxDof(section, &maxDof);
3393:   PetscSectionGetChart(section, &pStart, &pEnd);
3394:   PetscMalloc1(maxDof, &indices);
3395:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3396:   for (p = pStart; p < pEnd; ++p) {
3397:     PetscInt cdof, d;

3399:     PetscSectionGetConstraintDof(section, p, &cdof);
3400:     if (cdof) {
3401:       if (numFields) {
3402:         PetscInt numConst = 0, foff = 0;

3404:         for (f = 0; f < numFields; ++f) {
3405:           const PetscInt *find;
3406:           PetscInt        fcdof, fdof;

3408:           PetscSectionGetFieldDof(section, p, f, &fdof);
3409:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3410:           /* Change constraint numbering from field component to local dof number */
3411:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3412:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3413:           numConst += fcdof;
3414:           foff     += fdof;
3415:         }
3416:         if (cdof != numConst) {PetscSectionSetConstraintDof(section, p, numConst);}
3417:       } else {
3418:         for (d = 0; d < cdof; ++d) indices[d] = d;
3419:       }
3420:       PetscSectionSetConstraintIndices(section, p, indices);
3421:     }
3422:   }
3423:   PetscFree(indices);
3424:   return(0);
3425: }

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

3430:   Not Collective

3432:   Input Parameters:
3433: + dm        - The DMPlex object
3434: . dim       - The spatial dimension of the problem
3435: . numFields - The number of fields in the problem
3436: . numComp   - An array of size numFields that holds the number of components for each field
3437: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3438: . numBC     - The number of boundary conditions
3439: . bcField   - An array of size numBC giving the field number for each boundry condition
3440: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3441: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3442: - perm      - Optional permutation of the chart, or NULL

3444:   Output Parameter:
3445: . section - The PetscSection object

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

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

3452:   Level: developer

3454:   Fortran Notes:
3455:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3457: .keywords: mesh, elements
3458: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3459: @*/
3460: 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)
3461: {
3462:   PetscSection   aSec;

3466:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3467:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3468:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3469:   PetscSectionSetUp(*section);
3470:   DMPlexGetAnchors(dm,&aSec,NULL);
3471:   if (numBC || aSec) {
3472:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3473:     DMPlexCreateSectionBCIndices(dm, *section);
3474:   }
3475:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3476:   return(0);
3477: }

3479: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3480: {
3481:   PetscSection   section, s;
3482:   Mat            m;
3483:   PetscInt       maxHeight;

3487:   DMClone(dm, cdm);
3488:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3489:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3490:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3491:   DMSetDefaultSection(*cdm, section);
3492:   PetscSectionDestroy(&section);
3493:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3494:   MatCreate(PETSC_COMM_SELF, &m);
3495:   DMSetDefaultConstraints(*cdm, s, m);
3496:   PetscSectionDestroy(&s);
3497:   MatDestroy(&m);
3498:   return(0);
3499: }

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

3504:   Not Collective

3506:   Input Parameters:
3507: . dm        - The DMPlex object

3509:   Output Parameter:
3510: . section - The PetscSection object

3512:   Level: developer

3514: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3515: @*/
3516: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3517: {
3518:   DM_Plex *mesh = (DM_Plex*) dm->data;

3522:   if (section) *section = mesh->coneSection;
3523:   return(0);
3524: }

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

3529:   Not Collective

3531:   Input Parameters:
3532: . dm        - The DMPlex object

3534:   Output Parameter:
3535: . section - The PetscSection object

3537:   Level: developer

3539: .seealso: DMPlexGetConeSection()
3540: @*/
3541: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3542: {
3543:   DM_Plex *mesh = (DM_Plex*) dm->data;

3547:   if (section) *section = mesh->supportSection;
3548:   return(0);
3549: }

3551: /*@C
3552:   DMPlexGetCones - Return cone data

3554:   Not Collective

3556:   Input Parameters:
3557: . dm        - The DMPlex object

3559:   Output Parameter:
3560: . cones - The cone for each point

3562:   Level: developer

3564: .seealso: DMPlexGetConeSection()
3565: @*/
3566: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3567: {
3568:   DM_Plex *mesh = (DM_Plex*) dm->data;

3572:   if (cones) *cones = mesh->cones;
3573:   return(0);
3574: }

3576: /*@C
3577:   DMPlexGetConeOrientations - Return cone orientation data

3579:   Not Collective

3581:   Input Parameters:
3582: . dm        - The DMPlex object

3584:   Output Parameter:
3585: . coneOrientations - The cone orientation for each point

3587:   Level: developer

3589: .seealso: DMPlexGetConeSection()
3590: @*/
3591: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3592: {
3593:   DM_Plex *mesh = (DM_Plex*) dm->data;

3597:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3598:   return(0);
3599: }

3601: /******************************** FEM Support **********************************/

3603: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3604: {
3605:   DMLabel        label;
3606:   PetscInt      *perm;
3607:   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3611:   if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3612:   DMGetDimension(dm, &dim);
3613:   DMPlexGetDepthLabel(dm, &label);
3614:   DMLabelGetValue(label, point, &depth);
3615:   if (depth == 1) {eStart = point;}
3616:   else if  (depth == dim) {
3617:     const PetscInt *cone;

3619:     DMPlexGetCone(dm, point, &cone);
3620:     eStart = cone[0];
3621:   } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering", point, depth);
3622:   if (!section) {DMGetDefaultSection(dm, &section);}
3623:   PetscSectionGetNumFields(section, &Nf);
3624:   if (dim <= 1) return(0);
3625:   for (f = 0; f < Nf; ++f) {
3626:     /* An order k SEM disc has k-1 dofs on an edge */
3627:     PetscSectionGetFieldDof(section, eStart, f, &k);
3628:     PetscSectionGetFieldComponents(section, f, &Nc);
3629:     k = k/Nc + 1;
3630:     size += PetscPowInt(k+1, dim)*Nc;
3631:   }
3632:   PetscMalloc1(size, &perm);
3633:   for (f = 0; f < Nf; ++f) {
3634:     switch (dim) {
3635:     case 2:
3636:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3637:       PetscSectionGetFieldDof(section, eStart, f, &k);
3638:       PetscSectionGetFieldComponents(section, f, &Nc);
3639:       k = k/Nc + 1;
3640:       /* The SEM order is

3642:          v_lb, {e_b}, v_rb,
3643:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3644:          v_lt, reverse {e_t}, v_rt
3645:       */
3646:       {
3647:         const PetscInt of   = 0;
3648:         const PetscInt oeb  = of   + PetscSqr(k-1);
3649:         const PetscInt oer  = oeb  + (k-1);
3650:         const PetscInt oet  = oer  + (k-1);
3651:         const PetscInt oel  = oet  + (k-1);
3652:         const PetscInt ovlb = oel  + (k-1);
3653:         const PetscInt ovrb = ovlb + 1;
3654:         const PetscInt ovrt = ovrb + 1;
3655:         const PetscInt ovlt = ovrt + 1;
3656:         PetscInt       o;

3658:         /* bottom */
3659:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3660:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3661:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3662:         /* middle */
3663:         for (i = 0; i < k-1; ++i) {
3664:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3665:           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;
3666:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3667:         }
3668:         /* top */
3669:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3670:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3671:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3672:         foffset = offset;
3673:       }
3674:       break;
3675:     case 3:
3676:       /* The original hex closure is

3678:          {c,
3679:           f_b, f_t, f_f, f_b, f_r, f_l,
3680:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3681:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3682:       */
3683:       PetscSectionGetFieldDof(section, eStart, f, &k);
3684:       PetscSectionGetFieldComponents(section, f, &Nc);
3685:       k = k/Nc + 1;
3686:       /* The SEM order is
3687:          Bottom Slice
3688:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3689:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3690:          v_blb, {e_bb}, v_brb,

3692:          Middle Slice (j)
3693:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3694:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3695:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3697:          Top Slice
3698:          v_tlf, {e_tf}, v_trf,
3699:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3700:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3701:       */
3702:       {
3703:         const PetscInt oc    = 0;
3704:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3705:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3706:         const PetscInt off   = oft   + PetscSqr(k-1);
3707:         const PetscInt ofk   = off   + PetscSqr(k-1);
3708:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3709:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3710:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3711:         const PetscInt oebb  = oebl  + (k-1);
3712:         const PetscInt oebr  = oebb  + (k-1);
3713:         const PetscInt oebf  = oebr  + (k-1);
3714:         const PetscInt oetf  = oebf  + (k-1);
3715:         const PetscInt oetr  = oetf  + (k-1);
3716:         const PetscInt oetb  = oetr  + (k-1);
3717:         const PetscInt oetl  = oetb  + (k-1);
3718:         const PetscInt oerf  = oetl  + (k-1);
3719:         const PetscInt oelf  = oerf  + (k-1);
3720:         const PetscInt oelb  = oelf  + (k-1);
3721:         const PetscInt oerb  = oelb  + (k-1);
3722:         const PetscInt ovblf = oerb  + (k-1);
3723:         const PetscInt ovblb = ovblf + 1;
3724:         const PetscInt ovbrb = ovblb + 1;
3725:         const PetscInt ovbrf = ovbrb + 1;
3726:         const PetscInt ovtlf = ovbrf + 1;
3727:         const PetscInt ovtrf = ovtlf + 1;
3728:         const PetscInt ovtrb = ovtrf + 1;
3729:         const PetscInt ovtlb = ovtrb + 1;
3730:         PetscInt       o, n;

3732:         /* Bottom Slice */
3733:         /*   bottom */
3734:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3735:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3736:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3737:         /*   middle */
3738:         for (i = 0; i < k-1; ++i) {
3739:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3740:           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;}
3741:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3742:         }
3743:         /*   top */
3744:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3745:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3746:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3748:         /* Middle Slice */
3749:         for (j = 0; j < k-1; ++j) {
3750:           /*   bottom */
3751:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3752:           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;
3753:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3754:           /*   middle */
3755:           for (i = 0; i < k-1; ++i) {
3756:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3757:             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;
3758:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3759:           }
3760:           /*   top */
3761:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3762:           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;
3763:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3764:         }

3766:         /* Top Slice */
3767:         /*   bottom */
3768:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3769:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3770:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3771:         /*   middle */
3772:         for (i = 0; i < k-1; ++i) {
3773:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3774:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3775:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3776:         }
3777:         /*   top */
3778:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3779:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3780:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3782:         foffset = offset;
3783:       }
3784:       break;
3785:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3786:     }
3787:   }
3788:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3789:   /* Check permutation */
3790:   {
3791:     PetscInt *check;

3793:     PetscMalloc1(size, &check);
3794:     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]);}
3795:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3796:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3797:     PetscFree(check);
3798:   }
3799:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3800:   return(0);
3801: }

3803: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3804: {
3805:   PetscDS        prob;
3806:   PetscInt       depth, Nf, h;
3807:   DMLabel        label;

3811:   prob    = dm->prob;
3812:   Nf      = prob->Nf;
3813:   label   = dm->depthLabel;
3814:   *dspace = NULL;
3815:   if (field < Nf) {
3816:     PetscObject disc = prob->disc[field];

3818:     if (disc->classid == PETSCFE_CLASSID) {
3819:       PetscDualSpace dsp;

3821:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3822:       DMLabelGetNumValues(label,&depth);
3823:       DMLabelGetValue(label,point,&h);
3824:       h    = depth - 1 - h;
3825:       if (h) {
3826:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3827:       } else {
3828:         *dspace = dsp;
3829:       }
3830:     }
3831:   }
3832:   return(0);
3833: }


3836: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3837: {
3838:   PetscScalar    *array, *vArray;
3839:   const PetscInt *cone, *coneO;
3840:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3841:   PetscErrorCode  ierr;

3844:   PetscSectionGetChart(section, &pStart, &pEnd);
3845:   DMPlexGetConeSize(dm, point, &numPoints);
3846:   DMPlexGetCone(dm, point, &cone);
3847:   DMPlexGetConeOrientation(dm, point, &coneO);
3848:   if (!values || !*values) {
3849:     if ((point >= pStart) && (point < pEnd)) {
3850:       PetscInt dof;

3852:       PetscSectionGetDof(section, point, &dof);
3853:       size += dof;
3854:     }
3855:     for (p = 0; p < numPoints; ++p) {
3856:       const PetscInt cp = cone[p];
3857:       PetscInt       dof;

3859:       if ((cp < pStart) || (cp >= pEnd)) continue;
3860:       PetscSectionGetDof(section, cp, &dof);
3861:       size += dof;
3862:     }
3863:     if (!values) {
3864:       if (csize) *csize = size;
3865:       return(0);
3866:     }
3867:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
3868:   } else {
3869:     array = *values;
3870:   }
3871:   size = 0;
3872:   VecGetArray(v, &vArray);
3873:   if ((point >= pStart) && (point < pEnd)) {
3874:     PetscInt     dof, off, d;
3875:     PetscScalar *varr;

3877:     PetscSectionGetDof(section, point, &dof);
3878:     PetscSectionGetOffset(section, point, &off);
3879:     varr = &vArray[off];
3880:     for (d = 0; d < dof; ++d, ++offset) {
3881:       array[offset] = varr[d];
3882:     }
3883:     size += dof;
3884:   }
3885:   for (p = 0; p < numPoints; ++p) {
3886:     const PetscInt cp = cone[p];
3887:     PetscInt       o  = coneO[p];
3888:     PetscInt       dof, off, d;
3889:     PetscScalar   *varr;

3891:     if ((cp < pStart) || (cp >= pEnd)) continue;
3892:     PetscSectionGetDof(section, cp, &dof);
3893:     PetscSectionGetOffset(section, cp, &off);
3894:     varr = &vArray[off];
3895:     if (o >= 0) {
3896:       for (d = 0; d < dof; ++d, ++offset) {
3897:         array[offset] = varr[d];
3898:       }
3899:     } else {
3900:       for (d = dof-1; d >= 0; --d, ++offset) {
3901:         array[offset] = varr[d];
3902:       }
3903:     }
3904:     size += dof;
3905:   }
3906:   VecRestoreArray(v, &vArray);
3907:   if (!*values) {
3908:     if (csize) *csize = size;
3909:     *values = array;
3910:   } else {
3911:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3912:     *csize = size;
3913:   }
3914:   return(0);
3915: }

3917: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3918: {
3919:   const PetscInt *cla;
3920:   PetscInt       np, *pts = NULL;

3924:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3925:   if (!*clPoints) {
3926:     PetscInt pStart, pEnd, p, q;

3928:     PetscSectionGetChart(section, &pStart, &pEnd);
3929:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3930:     /* Compress out points not in the section */
3931:     for (p = 0, q = 0; p < np; p++) {
3932:       PetscInt r = pts[2*p];
3933:       if ((r >= pStart) && (r < pEnd)) {
3934:         pts[q*2]   = r;
3935:         pts[q*2+1] = pts[2*p+1];
3936:         ++q;
3937:       }
3938:     }
3939:     np = q;
3940:     cla = NULL;
3941:   } else {
3942:     PetscInt dof, off;

3944:     PetscSectionGetDof(*clSec, point, &dof);
3945:     PetscSectionGetOffset(*clSec, point, &off);
3946:     ISGetIndices(*clPoints, &cla);
3947:     np   = dof/2;
3948:     pts  = (PetscInt *) &cla[off];
3949:   }
3950:   *numPoints = np;
3951:   *points    = pts;
3952:   *clp       = cla;

3954:   return(0);
3955: }

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

3962:   if (!*clPoints) {
3963:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3964:   } else {
3965:     ISRestoreIndices(*clPoints, clp);
3966:   }
3967:   *numPoints = 0;
3968:   *points    = NULL;
3969:   *clSec     = NULL;
3970:   *clPoints  = NULL;
3971:   *clp       = NULL;
3972:   return(0);
3973: }

3975: 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[])
3976: {
3977:   PetscInt          offset = 0, p;
3978:   const PetscInt    **perms = NULL;
3979:   const PetscScalar **flips = NULL;
3980:   PetscErrorCode    ierr;

3983:   *size = 0;
3984:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3985:   for (p = 0; p < numPoints; p++) {
3986:     const PetscInt    point = points[2*p];
3987:     const PetscInt    *perm = perms ? perms[p] : NULL;
3988:     const PetscScalar *flip = flips ? flips[p] : NULL;
3989:     PetscInt          dof, off, d;
3990:     const PetscScalar *varr;

3992:     PetscSectionGetDof(section, point, &dof);
3993:     PetscSectionGetOffset(section, point, &off);
3994:     varr = &vArray[off];
3995:     if (clperm) {
3996:       if (perm) {
3997:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3998:       } else {
3999:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4000:       }
4001:       if (flip) {
4002:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4003:       }
4004:     } else {
4005:       if (perm) {
4006:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4007:       } else {
4008:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4009:       }
4010:       if (flip) {
4011:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4012:       }
4013:     }
4014:     offset += dof;
4015:   }
4016:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4017:   *size = offset;
4018:   return(0);
4019: }

4021: 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[])
4022: {
4023:   PetscInt          offset = 0, f;
4024:   PetscErrorCode    ierr;

4027:   *size = 0;
4028:   for (f = 0; f < numFields; ++f) {
4029:     PetscInt          p;
4030:     const PetscInt    **perms = NULL;
4031:     const PetscScalar **flips = NULL;

4033:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4034:     for (p = 0; p < numPoints; p++) {
4035:       const PetscInt    point = points[2*p];
4036:       PetscInt          fdof, foff, b;
4037:       const PetscScalar *varr;
4038:       const PetscInt    *perm = perms ? perms[p] : NULL;
4039:       const PetscScalar *flip = flips ? flips[p] : NULL;

4041:       PetscSectionGetFieldDof(section, point, f, &fdof);
4042:       PetscSectionGetFieldOffset(section, point, f, &foff);
4043:       varr = &vArray[foff];
4044:       if (clperm) {
4045:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4046:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4047:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4048:       } else {
4049:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4050:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4051:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4052:       }
4053:       offset += fdof;
4054:     }
4055:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4056:   }
4057:   *size = offset;
4058:   return(0);
4059: }

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

4064:   Not collective

4066:   Input Parameters:
4067: + dm - The DM
4068: . section - The section describing the layout in v, or NULL to use the default section
4069: . v - The local vector
4070: . point - The point in the DM
4071: . csize - The size of the input values array, or NULL
4072: - values - An array to use for the values, or NULL to have it allocated automatically

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

4078: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4079: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4080: $ assembly function, and a user may already have allocated storage for this operation.
4081: $
4082: $ A typical use could be
4083: $
4084: $  values = NULL;
4085: $  DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4086: $  for (cl = 0; cl < clSize; ++cl) {
4087: $    <Compute on closure>
4088: $  }
4089: $  DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4090: $
4091: $ or
4092: $
4093: $  PetscMalloc1(clMaxSize, &values);
4094: $  for (p = pStart; p < pEnd; ++p) {
4095: $    clSize = clMaxSize;
4096: $    DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4097: $    for (cl = 0; cl < clSize; ++cl) {
4098: $      <Compute on closure>
4099: $    }
4100: $  }
4101: $  PetscFree(values);

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

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

4109:   Level: intermediate

4111: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4112: @*/
4113: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4114: {
4115:   PetscSection       clSection;
4116:   IS                 clPoints;
4117:   PetscScalar       *array;
4118:   const PetscScalar *vArray;
4119:   PetscInt          *points = NULL;
4120:   const PetscInt    *clp, *perm;
4121:   PetscInt           depth, numFields, numPoints, size;
4122:   PetscErrorCode     ierr;

4126:   if (!section) {DMGetDefaultSection(dm, &section);}
4129:   DMPlexGetDepth(dm, &depth);
4130:   PetscSectionGetNumFields(section, &numFields);
4131:   if (depth == 1 && numFields < 2) {
4132:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4133:     return(0);
4134:   }
4135:   /* Get points */
4136:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4137:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4138:   /* Get array */
4139:   if (!values || !*values) {
4140:     PetscInt asize = 0, dof, p;

4142:     for (p = 0; p < numPoints*2; p += 2) {
4143:       PetscSectionGetDof(section, points[p], &dof);
4144:       asize += dof;
4145:     }
4146:     if (!values) {
4147:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4148:       if (csize) *csize = asize;
4149:       return(0);
4150:     }
4151:     DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4152:   } else {
4153:     array = *values;
4154:   }
4155:   VecGetArrayRead(v, &vArray);
4156:   /* Get values */
4157:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4158:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4159:   /* Cleanup points */
4160:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4161:   /* Cleanup array */
4162:   VecRestoreArrayRead(v, &vArray);
4163:   if (!*values) {
4164:     if (csize) *csize = size;
4165:     *values = array;
4166:   } else {
4167:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4168:     *csize = size;
4169:   }
4170:   return(0);
4171: }

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

4176:   Not collective

4178:   Input Parameters:
4179: + dm - The DM
4180: . section - The section describing the layout in v, or NULL to use the default section
4181: . v - The local vector
4182: . point - The point in the DM
4183: . csize - The number of values in the closure, or NULL
4184: - values - The array of values, which is a borrowed array and should not be freed

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

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

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

4194:   Level: intermediate

4196: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4197: @*/
4198: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4199: {
4200:   PetscInt       size = 0;

4204:   /* Should work without recalculating size */
4205:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4206:   *values = NULL;
4207:   return(0);
4208: }

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

4213: 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[])
4214: {
4215:   PetscInt        cdof;   /* The number of constraints on this point */
4216:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4217:   PetscScalar    *a;
4218:   PetscInt        off, cind = 0, k;
4219:   PetscErrorCode  ierr;

4222:   PetscSectionGetConstraintDof(section, point, &cdof);
4223:   PetscSectionGetOffset(section, point, &off);
4224:   a    = &array[off];
4225:   if (!cdof || setBC) {
4226:     if (clperm) {
4227:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4228:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4229:     } else {
4230:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4231:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4232:     }
4233:   } else {
4234:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4235:     if (clperm) {
4236:       if (perm) {for (k = 0; k < dof; ++k) {
4237:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4238:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4239:         }
4240:       } else {
4241:         for (k = 0; k < dof; ++k) {
4242:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4243:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4244:         }
4245:       }
4246:     } else {
4247:       if (perm) {
4248:         for (k = 0; k < dof; ++k) {
4249:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4250:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4251:         }
4252:       } else {
4253:         for (k = 0; k < dof; ++k) {
4254:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4255:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4256:         }
4257:       }
4258:     }
4259:   }
4260:   return(0);
4261: }

4263: 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[])
4264: {
4265:   PetscInt        cdof;   /* The number of constraints on this point */
4266:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4267:   PetscScalar    *a;
4268:   PetscInt        off, cind = 0, k;
4269:   PetscErrorCode  ierr;

4272:   PetscSectionGetConstraintDof(section, point, &cdof);
4273:   PetscSectionGetOffset(section, point, &off);
4274:   a    = &array[off];
4275:   if (cdof) {
4276:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4277:     if (clperm) {
4278:       if (perm) {
4279:         for (k = 0; k < dof; ++k) {
4280:           if ((cind < cdof) && (k == cdofs[cind])) {
4281:             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4282:             cind++;
4283:           }
4284:         }
4285:       } else {
4286:         for (k = 0; k < dof; ++k) {
4287:           if ((cind < cdof) && (k == cdofs[cind])) {
4288:             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4289:             cind++;
4290:           }
4291:         }
4292:       }
4293:     } else {
4294:       if (perm) {
4295:         for (k = 0; k < dof; ++k) {
4296:           if ((cind < cdof) && (k == cdofs[cind])) {
4297:             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4298:             cind++;
4299:           }
4300:         }
4301:       } else {
4302:         for (k = 0; k < dof; ++k) {
4303:           if ((cind < cdof) && (k == cdofs[cind])) {
4304:             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4305:             cind++;
4306:           }
4307:         }
4308:       }
4309:     }
4310:   }
4311:   return(0);
4312: }

4314: 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[])
4315: {
4316:   PetscScalar    *a;
4317:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4318:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4319:   PetscInt        cind = 0, b;
4320:   PetscErrorCode  ierr;

4323:   PetscSectionGetFieldDof(section, point, f, &fdof);
4324:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4325:   PetscSectionGetFieldOffset(section, point, f, &foff);
4326:   a    = &array[foff];
4327:   if (!fcdof || setBC) {
4328:     if (clperm) {
4329:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4330:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4331:     } else {
4332:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4333:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4334:     }
4335:   } else {
4336:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4337:     if (clperm) {
4338:       if (perm) {
4339:         for (b = 0; b < fdof; b++) {
4340:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4341:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4342:         }
4343:       } else {
4344:         for (b = 0; b < fdof; b++) {
4345:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4346:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4347:         }
4348:       }
4349:     } else {
4350:       if (perm) {
4351:         for (b = 0; b < fdof; b++) {
4352:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4353:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4354:         }
4355:       } else {
4356:         for (b = 0; b < fdof; b++) {
4357:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4358:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4359:         }
4360:       }
4361:     }
4362:   }
4363:   *offset += fdof;
4364:   return(0);
4365: }

4367: PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4368: {
4369:   PetscScalar    *a;
4370:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4371:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4372:   PetscInt        cind = 0, ncind = 0, b;
4373:   PetscBool       ncSet, fcSet;
4374:   PetscErrorCode  ierr;

4377:   PetscSectionGetFieldDof(section, point, f, &fdof);
4378:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4379:   PetscSectionGetFieldOffset(section, point, f, &foff);
4380:   a    = &array[foff];
4381:   if (fcdof) {
4382:     /* We just override fcdof and fcdofs with Ncc and comps */
4383:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4384:     if (clperm) {
4385:       if (perm) {
4386:         if (comps) {
4387:           for (b = 0; b < fdof; b++) {
4388:             ncSet = fcSet = PETSC_FALSE;
4389:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4390:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4391:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4392:           }
4393:         } else {
4394:           for (b = 0; b < fdof; b++) {
4395:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4396:               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4397:               ++cind;
4398:             }
4399:           }
4400:         }
4401:       } else {
4402:         if (comps) {
4403:           for (b = 0; b < fdof; b++) {
4404:             ncSet = fcSet = PETSC_FALSE;
4405:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4406:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4407:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4408:           }
4409:         } else {
4410:           for (b = 0; b < fdof; b++) {
4411:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4412:               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4413:               ++cind;
4414:             }
4415:           }
4416:         }
4417:       }
4418:     } else {
4419:       if (perm) {
4420:         if (comps) {
4421:           for (b = 0; b < fdof; b++) {
4422:             ncSet = fcSet = PETSC_FALSE;
4423:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4424:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4425:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4426:           }
4427:         } else {
4428:           for (b = 0; b < fdof; b++) {
4429:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4430:               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4431:               ++cind;
4432:             }
4433:           }
4434:         }
4435:       } else {
4436:         if (comps) {
4437:           for (b = 0; b < fdof; b++) {
4438:             ncSet = fcSet = PETSC_FALSE;
4439:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4440:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4441:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4442:           }
4443:         } else {
4444:           for (b = 0; b < fdof; b++) {
4445:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4446:               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4447:               ++cind;
4448:             }
4449:           }
4450:         }
4451:       }
4452:     }
4453:   }
4454:   *offset += fdof;
4455:   return(0);
4456: }

4458: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4459: {
4460:   PetscScalar    *array;
4461:   const PetscInt *cone, *coneO;
4462:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4463:   PetscErrorCode  ierr;

4466:   PetscSectionGetChart(section, &pStart, &pEnd);
4467:   DMPlexGetConeSize(dm, point, &numPoints);
4468:   DMPlexGetCone(dm, point, &cone);
4469:   DMPlexGetConeOrientation(dm, point, &coneO);
4470:   VecGetArray(v, &array);
4471:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4472:     const PetscInt cp = !p ? point : cone[p-1];
4473:     const PetscInt o  = !p ? 0     : coneO[p-1];

4475:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4476:     PetscSectionGetDof(section, cp, &dof);
4477:     /* ADD_VALUES */
4478:     {
4479:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4480:       PetscScalar    *a;
4481:       PetscInt        cdof, coff, cind = 0, k;

4483:       PetscSectionGetConstraintDof(section, cp, &cdof);
4484:       PetscSectionGetOffset(section, cp, &coff);
4485:       a    = &array[coff];
4486:       if (!cdof) {
4487:         if (o >= 0) {
4488:           for (k = 0; k < dof; ++k) {
4489:             a[k] += values[off+k];
4490:           }
4491:         } else {
4492:           for (k = 0; k < dof; ++k) {
4493:             a[k] += values[off+dof-k-1];
4494:           }
4495:         }
4496:       } else {
4497:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4498:         if (o >= 0) {
4499:           for (k = 0; k < dof; ++k) {
4500:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4501:             a[k] += values[off+k];
4502:           }
4503:         } else {
4504:           for (k = 0; k < dof; ++k) {
4505:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4506:             a[k] += values[off+dof-k-1];
4507:           }
4508:         }
4509:       }
4510:     }
4511:   }
4512:   VecRestoreArray(v, &array);
4513:   return(0);
4514: }

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

4519:   Not collective

4521:   Input Parameters:
4522: + dm - The DM
4523: . section - The section describing the layout in v, or NULL to use the default section
4524: . v - The local vector
4525: . point - The point in the DM
4526: . values - The array of values
4527: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4528:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

4533:   Level: intermediate

4535: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4536: @*/
4537: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4538: {
4539:   PetscSection    clSection;
4540:   IS              clPoints;
4541:   PetscScalar    *array;
4542:   PetscInt       *points = NULL;
4543:   const PetscInt *clp, *clperm;
4544:   PetscInt        depth, numFields, numPoints, p;
4545:   PetscErrorCode  ierr;

4549:   if (!section) {DMGetDefaultSection(dm, &section);}
4552:   DMPlexGetDepth(dm, &depth);
4553:   PetscSectionGetNumFields(section, &numFields);
4554:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4555:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4556:     return(0);
4557:   }
4558:   /* Get points */
4559:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4560:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4561:   /* Get array */
4562:   VecGetArray(v, &array);
4563:   /* Get values */
4564:   if (numFields > 0) {
4565:     PetscInt offset = 0, f;
4566:     for (f = 0; f < numFields; ++f) {
4567:       const PetscInt    **perms = NULL;
4568:       const PetscScalar **flips = NULL;

4570:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4571:       switch (mode) {
4572:       case INSERT_VALUES:
4573:         for (p = 0; p < numPoints; p++) {
4574:           const PetscInt    point = points[2*p];
4575:           const PetscInt    *perm = perms ? perms[p] : NULL;
4576:           const PetscScalar *flip = flips ? flips[p] : NULL;
4577:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4578:         } break;
4579:       case INSERT_ALL_VALUES:
4580:         for (p = 0; p < numPoints; p++) {
4581:           const PetscInt    point = points[2*p];
4582:           const PetscInt    *perm = perms ? perms[p] : NULL;
4583:           const PetscScalar *flip = flips ? flips[p] : NULL;
4584:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4585:         } break;
4586:       case INSERT_BC_VALUES:
4587:         for (p = 0; p < numPoints; p++) {
4588:           const PetscInt    point = points[2*p];
4589:           const PetscInt    *perm = perms ? perms[p] : NULL;
4590:           const PetscScalar *flip = flips ? flips[p] : NULL;
4591:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4592:         } break;
4593:       case ADD_VALUES:
4594:         for (p = 0; p < numPoints; p++) {
4595:           const PetscInt    point = points[2*p];
4596:           const PetscInt    *perm = perms ? perms[p] : NULL;
4597:           const PetscScalar *flip = flips ? flips[p] : NULL;
4598:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4599:         } break;
4600:       case ADD_ALL_VALUES:
4601:         for (p = 0; p < numPoints; p++) {
4602:           const PetscInt    point = points[2*p];
4603:           const PetscInt    *perm = perms ? perms[p] : NULL;
4604:           const PetscScalar *flip = flips ? flips[p] : NULL;
4605:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4606:         } break;
4607:       case ADD_BC_VALUES:
4608:         for (p = 0; p < numPoints; p++) {
4609:           const PetscInt    point = points[2*p];
4610:           const PetscInt    *perm = perms ? perms[p] : NULL;
4611:           const PetscScalar *flip = flips ? flips[p] : NULL;
4612:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4613:         } break;
4614:       default:
4615:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4616:       }
4617:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4618:     }
4619:   } else {
4620:     PetscInt dof, off;
4621:     const PetscInt    **perms = NULL;
4622:     const PetscScalar **flips = NULL;

4624:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4625:     switch (mode) {
4626:     case INSERT_VALUES:
4627:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4628:         const PetscInt    point = points[2*p];
4629:         const PetscInt    *perm = perms ? perms[p] : NULL;
4630:         const PetscScalar *flip = flips ? flips[p] : NULL;
4631:         PetscSectionGetDof(section, point, &dof);
4632:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4633:       } break;
4634:     case INSERT_ALL_VALUES:
4635:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4636:         const PetscInt    point = points[2*p];
4637:         const PetscInt    *perm = perms ? perms[p] : NULL;
4638:         const PetscScalar *flip = flips ? flips[p] : NULL;
4639:         PetscSectionGetDof(section, point, &dof);
4640:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4641:       } break;
4642:     case INSERT_BC_VALUES:
4643:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4644:         const PetscInt    point = points[2*p];
4645:         const PetscInt    *perm = perms ? perms[p] : NULL;
4646:         const PetscScalar *flip = flips ? flips[p] : NULL;
4647:         PetscSectionGetDof(section, point, &dof);
4648:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4649:       } break;
4650:     case ADD_VALUES:
4651:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4652:         const PetscInt    point = points[2*p];
4653:         const PetscInt    *perm = perms ? perms[p] : NULL;
4654:         const PetscScalar *flip = flips ? flips[p] : NULL;
4655:         PetscSectionGetDof(section, point, &dof);
4656:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4657:       } break;
4658:     case ADD_ALL_VALUES:
4659:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4660:         const PetscInt    point = points[2*p];
4661:         const PetscInt    *perm = perms ? perms[p] : NULL;
4662:         const PetscScalar *flip = flips ? flips[p] : NULL;
4663:         PetscSectionGetDof(section, point, &dof);
4664:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4665:       } break;
4666:     case ADD_BC_VALUES:
4667:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4668:         const PetscInt    point = points[2*p];
4669:         const PetscInt    *perm = perms ? perms[p] : NULL;
4670:         const PetscScalar *flip = flips ? flips[p] : NULL;
4671:         PetscSectionGetDof(section, point, &dof);
4672:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4673:       } break;
4674:     default:
4675:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4676:     }
4677:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4678:   }
4679:   /* Cleanup points */
4680:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4681:   /* Cleanup array */
4682:   VecRestoreArray(v, &array);
4683:   return(0);
4684: }

4686: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4687: {
4688:   PetscSection      clSection;
4689:   IS                clPoints;
4690:   PetscScalar       *array;
4691:   PetscInt          *points = NULL;
4692:   const PetscInt    *clp, *clperm;
4693:   PetscInt          numFields, numPoints, p;
4694:   PetscInt          offset = 0, f;
4695:   PetscErrorCode    ierr;

4699:   if (!section) {DMGetDefaultSection(dm, &section);}
4702:   PetscSectionGetNumFields(section, &numFields);
4703:   /* Get points */
4704:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4705:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4706:   /* Get array */
4707:   VecGetArray(v, &array);
4708:   /* Get values */
4709:   for (f = 0; f < numFields; ++f) {
4710:     const PetscInt    **perms = NULL;
4711:     const PetscScalar **flips = NULL;

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

4770: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4771: {
4772:   PetscMPIInt    rank;
4773:   PetscInt       i, j;

4777:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4778:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4779:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4780:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4781:   numCIndices = numCIndices ? numCIndices : numRIndices;
4782:   for (i = 0; i < numRIndices; i++) {
4783:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4784:     for (j = 0; j < numCIndices; j++) {
4785: #if defined(PETSC_USE_COMPLEX)
4786:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4787: #else
4788:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4789: #endif
4790:     }
4791:     PetscViewerASCIIPrintf(viewer, "\n");
4792:   }
4793:   return(0);
4794: }

4796: /* . off - The global offset of this point */
4797: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4798: {
4799:   PetscInt        dof;    /* The number of unknowns on this point */
4800:   PetscInt        cdof;   /* The number of constraints on this point */
4801:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4802:   PetscInt        cind = 0, k;
4803:   PetscErrorCode  ierr;

4806:   PetscSectionGetDof(section, point, &dof);
4807:   PetscSectionGetConstraintDof(section, point, &cdof);
4808:   if (!cdof || setBC) {
4809:     if (perm) {
4810:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4811:     } else {
4812:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4813:     }
4814:   } else {
4815:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4816:     if (perm) {
4817:       for (k = 0; k < dof; ++k) {
4818:         if ((cind < cdof) && (k == cdofs[cind])) {
4819:           /* Insert check for returning constrained indices */
4820:           indices[*loff+perm[k]] = -(off+k+1);
4821:           ++cind;
4822:         } else {
4823:           indices[*loff+perm[k]] = off+k-cind;
4824:         }
4825:       }
4826:     } else {
4827:       for (k = 0; k < dof; ++k) {
4828:         if ((cind < cdof) && (k == cdofs[cind])) {
4829:           /* Insert check for returning constrained indices */
4830:           indices[*loff+k] = -(off+k+1);
4831:           ++cind;
4832:         } else {
4833:           indices[*loff+k] = off+k-cind;
4834:         }
4835:       }
4836:     }
4837:   }
4838:   *loff += dof;
4839:   return(0);
4840: }

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

4849:   PetscSectionGetNumFields(section, &numFields);
4850:   for (f = 0, foff = 0; f < numFields; ++f) {
4851:     PetscInt        fdof, cfdof;
4852:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4853:     PetscInt        cind = 0, b;
4854:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4856:     PetscSectionGetFieldDof(section, point, f, &fdof);
4857:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4858:     if (!cfdof || setBC) {
4859:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4860:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4861:     } else {
4862:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4863:       if (perm) {
4864:         for (b = 0; b < fdof; b++) {
4865:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4866:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4867:             ++cind;
4868:           } else {
4869:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4870:           }
4871:         }
4872:       } else {
4873:         for (b = 0; b < fdof; b++) {
4874:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4875:             indices[foffs[f]+b] = -(off+foff+b+1);
4876:             ++cind;
4877:           } else {
4878:             indices[foffs[f]+b] = off+foff+b-cind;
4879:           }
4880:         }
4881:       }
4882:     }
4883:     foff     += (setBC ? fdof : (fdof - cfdof));
4884:     foffs[f] += fdof;
4885:   }
4886:   return(0);
4887: }

4889: 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)
4890: {
4891:   Mat             cMat;
4892:   PetscSection    aSec, cSec;
4893:   IS              aIS;
4894:   PetscInt        aStart = -1, aEnd = -1;
4895:   const PetscInt  *anchors;
4896:   PetscInt        numFields, f, p, q, newP = 0;
4897:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4898:   PetscInt        *newPoints, *indices, *newIndices;
4899:   PetscInt        maxAnchor, maxDof;
4900:   PetscInt        newOffsets[32];
4901:   PetscInt        *pointMatOffsets[32];
4902:   PetscInt        *newPointOffsets[32];
4903:   PetscScalar     *pointMat[32];
4904:   PetscScalar     *newValues=NULL,*tmpValues;
4905:   PetscBool       anyConstrained = PETSC_FALSE;
4906:   PetscErrorCode  ierr;

4911:   PetscSectionGetNumFields(section, &numFields);

4913:   DMPlexGetAnchors(dm,&aSec,&aIS);
4914:   /* if there are point-to-point constraints */
4915:   if (aSec) {
4916:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4917:     ISGetIndices(aIS,&anchors);
4918:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4919:     /* figure out how many points are going to be in the new element matrix
4920:      * (we allow double counting, because it's all just going to be summed
4921:      * into the global matrix anyway) */
4922:     for (p = 0; p < 2*numPoints; p+=2) {
4923:       PetscInt b    = points[p];
4924:       PetscInt bDof = 0, bSecDof;

4926:       PetscSectionGetDof(section,b,&bSecDof);
4927:       if (!bSecDof) {
4928:         continue;
4929:       }
4930:       if (b >= aStart && b < aEnd) {
4931:         PetscSectionGetDof(aSec,b,&bDof);
4932:       }
4933:       if (bDof) {
4934:         /* this point is constrained */
4935:         /* it is going to be replaced by its anchors */
4936:         PetscInt bOff, q;

4938:         anyConstrained = PETSC_TRUE;
4939:         newNumPoints  += bDof;
4940:         PetscSectionGetOffset(aSec,b,&bOff);
4941:         for (q = 0; q < bDof; q++) {
4942:           PetscInt a = anchors[bOff + q];
4943:           PetscInt aDof;

4945:           PetscSectionGetDof(section,a,&aDof);
4946:           newNumIndices += aDof;
4947:           for (f = 0; f < numFields; ++f) {
4948:             PetscInt fDof;

4950:             PetscSectionGetFieldDof(section, a, f, &fDof);
4951:             newOffsets[f+1] += fDof;
4952:           }
4953:         }
4954:       }
4955:       else {
4956:         /* this point is not constrained */
4957:         newNumPoints++;
4958:         newNumIndices += bSecDof;
4959:         for (f = 0; f < numFields; ++f) {
4960:           PetscInt fDof;

4962:           PetscSectionGetFieldDof(section, b, f, &fDof);
4963:           newOffsets[f+1] += fDof;
4964:         }
4965:       }
4966:     }
4967:   }
4968:   if (!anyConstrained) {
4969:     if (outNumPoints)  *outNumPoints  = 0;
4970:     if (outNumIndices) *outNumIndices = 0;
4971:     if (outPoints)     *outPoints     = NULL;
4972:     if (outValues)     *outValues     = NULL;
4973:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4974:     return(0);
4975:   }

4977:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4978:   if (outNumIndices) *outNumIndices = newNumIndices;

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

4982:   if (!outPoints && !outValues) {
4983:     if (offsets) {
4984:       for (f = 0; f <= numFields; f++) {
4985:         offsets[f] = newOffsets[f];
4986:       }
4987:     }
4988:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4989:     return(0);
4990:   }

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

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

4996:   /* workspaces */
4997:   if (numFields) {
4998:     for (f = 0; f < numFields; f++) {
4999:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5000:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5001:     }
5002:   }
5003:   else {
5004:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5005:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
5006:   }

5008:   /* get workspaces for the point-to-point matrices */
5009:   if (numFields) {
5010:     PetscInt totalOffset, totalMatOffset;

5012:     for (p = 0; p < numPoints; p++) {
5013:       PetscInt b    = points[2*p];
5014:       PetscInt bDof = 0, bSecDof;

5016:       PetscSectionGetDof(section,b,&bSecDof);
5017:       if (!bSecDof) {
5018:         for (f = 0; f < numFields; f++) {
5019:           newPointOffsets[f][p + 1] = 0;
5020:           pointMatOffsets[f][p + 1] = 0;
5021:         }
5022:         continue;
5023:       }
5024:       if (b >= aStart && b < aEnd) {
5025:         PetscSectionGetDof(aSec, b, &bDof);
5026:       }
5027:       if (bDof) {
5028:         for (f = 0; f < numFields; f++) {
5029:           PetscInt fDof, q, bOff, allFDof = 0;

5031:           PetscSectionGetFieldDof(section, b, f, &fDof);
5032:           PetscSectionGetOffset(aSec, b, &bOff);
5033:           for (q = 0; q < bDof; q++) {
5034:             PetscInt a = anchors[bOff + q];
5035:             PetscInt aFDof;

5037:             PetscSectionGetFieldDof(section, a, f, &aFDof);
5038:             allFDof += aFDof;
5039:           }
5040:           newPointOffsets[f][p+1] = allFDof;
5041:           pointMatOffsets[f][p+1] = fDof * allFDof;
5042:         }
5043:       }
5044:       else {
5045:         for (f = 0; f < numFields; f++) {
5046:           PetscInt fDof;

5048:           PetscSectionGetFieldDof(section, b, f, &fDof);
5049:           newPointOffsets[f][p+1] = fDof;
5050:           pointMatOffsets[f][p+1] = 0;
5051:         }
5052:       }
5053:     }
5054:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5055:       newPointOffsets[f][0] = totalOffset;
5056:       pointMatOffsets[f][0] = totalMatOffset;
5057:       for (p = 0; p < numPoints; p++) {
5058:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5059:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5060:       }
5061:       totalOffset    = newPointOffsets[f][numPoints];
5062:       totalMatOffset = pointMatOffsets[f][numPoints];
5063:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5064:     }
5065:   }
5066:   else {
5067:     for (p = 0; p < numPoints; p++) {
5068:       PetscInt b    = points[2*p];
5069:       PetscInt bDof = 0, bSecDof;

5071:       PetscSectionGetDof(section,b,&bSecDof);
5072:       if (!bSecDof) {
5073:         newPointOffsets[0][p + 1] = 0;
5074:         pointMatOffsets[0][p + 1] = 0;
5075:         continue;
5076:       }
5077:       if (b >= aStart && b < aEnd) {
5078:         PetscSectionGetDof(aSec, b, &bDof);
5079:       }
5080:       if (bDof) {
5081:         PetscInt bOff, q, allDof = 0;

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

5087:           PetscSectionGetDof(section, a, &aDof);
5088:           allDof += aDof;
5089:         }
5090:         newPointOffsets[0][p+1] = allDof;
5091:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5092:       }
5093:       else {
5094:         newPointOffsets[0][p+1] = bSecDof;
5095:         pointMatOffsets[0][p+1] = 0;
5096:       }
5097:     }
5098:     newPointOffsets[0][0] = 0;
5099:     pointMatOffsets[0][0] = 0;
5100:     for (p = 0; p < numPoints; p++) {
5101:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5102:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5103:     }
5104:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5105:   }

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

5110:   /* get the point-to-point matrices; construct newPoints */
5111:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5112:   PetscSectionGetMaxDof(section, &maxDof);
5113:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5114:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5115:   if (numFields) {
5116:     for (p = 0, newP = 0; p < numPoints; p++) {
5117:       PetscInt b    = points[2*p];
5118:       PetscInt o    = points[2*p+1];
5119:       PetscInt bDof = 0, bSecDof;

5121:       PetscSectionGetDof(section, b, &bSecDof);
5122:       if (!bSecDof) {
5123:         continue;
5124:       }
5125:       if (b >= aStart && b < aEnd) {
5126:         PetscSectionGetDof(aSec, b, &bDof);
5127:       }
5128:       if (bDof) {
5129:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5131:         fStart[0] = 0;
5132:         fEnd[0]   = 0;
5133:         for (f = 0; f < numFields; f++) {
5134:           PetscInt fDof;

5136:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5137:           fStart[f+1] = fStart[f] + fDof;
5138:           fEnd[f+1]   = fStart[f+1];
5139:         }
5140:         PetscSectionGetOffset(cSec, b, &bOff);
5141:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

5143:         fAnchorStart[0] = 0;
5144:         fAnchorEnd[0]   = 0;
5145:         for (f = 0; f < numFields; f++) {
5146:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5148:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5149:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5150:         }
5151:         PetscSectionGetOffset(aSec, b, &bOff);
5152:         for (q = 0; q < bDof; q++) {
5153:           PetscInt a = anchors[bOff + q], aOff;

5155:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5156:           newPoints[2*(newP + q)]     = a;
5157:           newPoints[2*(newP + q) + 1] = 0;
5158:           PetscSectionGetOffset(section, a, &aOff);
5159:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5160:         }
5161:         newP += bDof;

5163:         if (outValues) {
5164:           /* get the point-to-point submatrix */
5165:           for (f = 0; f < numFields; f++) {
5166:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5167:           }
5168:         }
5169:       }
5170:       else {
5171:         newPoints[2 * newP]     = b;
5172:         newPoints[2 * newP + 1] = o;
5173:         newP++;
5174:       }
5175:     }
5176:   } else {
5177:     for (p = 0; p < numPoints; p++) {
5178:       PetscInt b    = points[2*p];
5179:       PetscInt o    = points[2*p+1];
5180:       PetscInt bDof = 0, bSecDof;

5182:       PetscSectionGetDof(section, b, &bSecDof);
5183:       if (!bSecDof) {
5184:         continue;
5185:       }
5186:       if (b >= aStart && b < aEnd) {
5187:         PetscSectionGetDof(aSec, b, &bDof);
5188:       }
5189:       if (bDof) {
5190:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5201:           newPoints[2*(newP + q)]     = a;
5202:           newPoints[2*(newP + q) + 1] = 0;
5203:           PetscSectionGetOffset(section, a, &aOff);
5204:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5205:         }
5206:         newP += bDof;

5208:         /* get the point-to-point submatrix */
5209:         if (outValues) {
5210:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5211:         }
5212:       }
5213:       else {
5214:         newPoints[2 * newP]     = b;
5215:         newPoints[2 * newP + 1] = o;
5216:         newP++;
5217:       }
5218:     }
5219:   }

5221:   if (outValues) {
5222:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5223:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5224:     /* multiply constraints on the right */
5225:     if (numFields) {
5226:       for (f = 0; f < numFields; f++) {
5227:         PetscInt oldOff = offsets[f];

5229:         for (p = 0; p < numPoints; p++) {
5230:           PetscInt cStart = newPointOffsets[f][p];
5231:           PetscInt b      = points[2 * p];
5232:           PetscInt c, r, k;
5233:           PetscInt dof;

5235:           PetscSectionGetFieldDof(section,b,f,&dof);
5236:           if (!dof) {
5237:             continue;
5238:           }
5239:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5240:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5241:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5243:             for (r = 0; r < numIndices; r++) {
5244:               for (c = 0; c < nCols; c++) {
5245:                 for (k = 0; k < dof; k++) {
5246:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5247:                 }
5248:               }
5249:             }
5250:           }
5251:           else {
5252:             /* copy this column as is */
5253:             for (r = 0; r < numIndices; r++) {
5254:               for (c = 0; c < dof; c++) {
5255:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5256:               }
5257:             }
5258:           }
5259:           oldOff += dof;
5260:         }
5261:       }
5262:     }
5263:     else {
5264:       PetscInt oldOff = 0;
5265:       for (p = 0; p < numPoints; p++) {
5266:         PetscInt cStart = newPointOffsets[0][p];
5267:         PetscInt b      = points[2 * p];
5268:         PetscInt c, r, k;
5269:         PetscInt dof;

5271:         PetscSectionGetDof(section,b,&dof);
5272:         if (!dof) {
5273:           continue;
5274:         }
5275:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5276:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5277:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5279:           for (r = 0; r < numIndices; r++) {
5280:             for (c = 0; c < nCols; c++) {
5281:               for (k = 0; k < dof; k++) {
5282:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5283:               }
5284:             }
5285:           }
5286:         }
5287:         else {
5288:           /* copy this column as is */
5289:           for (r = 0; r < numIndices; r++) {
5290:             for (c = 0; c < dof; c++) {
5291:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5292:             }
5293:           }
5294:         }
5295:         oldOff += dof;
5296:       }
5297:     }

5299:     if (multiplyLeft) {
5300:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5301:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5302:       /* multiply constraints transpose on the left */
5303:       if (numFields) {
5304:         for (f = 0; f < numFields; f++) {
5305:           PetscInt oldOff = offsets[f];

5307:           for (p = 0; p < numPoints; p++) {
5308:             PetscInt rStart = newPointOffsets[f][p];
5309:             PetscInt b      = points[2 * p];
5310:             PetscInt c, r, k;
5311:             PetscInt dof;

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

5318:               for (r = 0; r < nRows; r++) {
5319:                 for (c = 0; c < newNumIndices; c++) {
5320:                   for (k = 0; k < dof; k++) {
5321:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5322:                   }
5323:                 }
5324:               }
5325:             }
5326:             else {
5327:               /* copy this row as is */
5328:               for (r = 0; r < dof; r++) {
5329:                 for (c = 0; c < newNumIndices; c++) {
5330:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5331:                 }
5332:               }
5333:             }
5334:             oldOff += dof;
5335:           }
5336:         }
5337:       }
5338:       else {
5339:         PetscInt oldOff = 0;

5341:         for (p = 0; p < numPoints; p++) {
5342:           PetscInt rStart = newPointOffsets[0][p];
5343:           PetscInt b      = points[2 * p];
5344:           PetscInt c, r, k;
5345:           PetscInt dof;

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

5352:             for (r = 0; r < nRows; r++) {
5353:               for (c = 0; c < newNumIndices; c++) {
5354:                 for (k = 0; k < dof; k++) {
5355:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5356:                 }
5357:               }
5358:             }
5359:           }
5360:           else {
5361:             /* copy this row as is */
5362:             for (r = 0; r < dof; r++) {
5363:               for (c = 0; c < newNumIndices; c++) {
5364:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5365:               }
5366:             }
5367:           }
5368:           oldOff += dof;
5369:         }
5370:       }

5372:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5373:     }
5374:     else {
5375:       newValues = tmpValues;
5376:     }
5377:   }

5379:   /* clean up */
5380:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5381:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5383:   if (numFields) {
5384:     for (f = 0; f < numFields; f++) {
5385:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5386:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5387:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5388:     }
5389:   }
5390:   else {
5391:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5392:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5393:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5394:   }
5395:   ISRestoreIndices(aIS,&anchors);

5397:   /* output */
5398:   if (outPoints) {
5399:     *outPoints = newPoints;
5400:   }
5401:   else {
5402:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5403:   }
5404:   if (outValues) {
5405:     *outValues = newValues;
5406:   }
5407:   for (f = 0; f <= numFields; f++) {
5408:     offsets[f] = newOffsets[f];
5409:   }
5410:   return(0);
5411: }

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

5416:   Not collective

5418:   Input Parameters:
5419: + dm - The DM
5420: . section - The section describing the layout in v, or NULL to use the default section
5421: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5422: - point - The mesh point

5424:   Output parameters:
5425: + numIndices - The number of indices
5426: . indices - The indices
5427: - outOffsets - Field offset if not NULL

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

5431:   Level: advanced

5433: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5434: @*/
5435: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5436: {
5437:   PetscSection    clSection;
5438:   IS              clPoints;
5439:   const PetscInt *clp;
5440:   const PetscInt  **perms[32] = {NULL};
5441:   PetscInt       *points = NULL, *pointsNew;
5442:   PetscInt        numPoints, numPointsNew;
5443:   PetscInt        offsets[32];
5444:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5445:   PetscErrorCode  ierr;

5453:   PetscSectionGetNumFields(section, &Nf);
5454:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5455:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5456:   /* Get points in closure */
5457:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5458:   /* Get number of indices and indices per field */
5459:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5460:     PetscInt dof, fdof;

5462:     PetscSectionGetDof(section, points[p], &dof);
5463:     for (f = 0; f < Nf; ++f) {
5464:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5465:       offsets[f+1] += fdof;
5466:     }
5467:     Nind += dof;
5468:   }
5469:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5470:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5471:   if (!Nf) offsets[1] = Nind;
5472:   /* Get dual space symmetries */
5473:   for (f = 0; f < PetscMax(1,Nf); f++) {
5474:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5475:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5476:   }
5477:   /* Correct for hanging node constraints */
5478:   {
5479:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5480:     if (numPointsNew) {
5481:       for (f = 0; f < PetscMax(1,Nf); f++) {
5482:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5483:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5484:       }
5485:       for (f = 0; f < PetscMax(1,Nf); f++) {
5486:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5487:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5488:       }
5489:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5490:       numPoints = numPointsNew;
5491:       Nind      = NindNew;
5492:       points    = pointsNew;
5493:     }
5494:   }
5495:   /* Calculate indices */
5496:   DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5497:   if (Nf) {
5498:     if (outOffsets) {
5499:       PetscInt f;

5501:       for (f = 0; f <= Nf; f++) {
5502:         outOffsets[f] = offsets[f];
5503:       }
5504:     }
5505:     for (p = 0; p < numPoints; p++) {
5506:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5507:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5508:     }
5509:   } else {
5510:     for (p = 0, off = 0; p < numPoints; p++) {
5511:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5513:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5514:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5515:     }
5516:   }
5517:   /* Cleanup points */
5518:   for (f = 0; f < PetscMax(1,Nf); f++) {
5519:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5520:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5521:   }
5522:   if (numPointsNew) {
5523:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5524:   } else {
5525:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5526:   }
5527:   if (numIndices) *numIndices = Nind;
5528:   return(0);
5529: }

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

5534:   Not collective

5536:   Input Parameters:
5537: + dm - The DM
5538: . section - The section describing the layout in v, or NULL to use the default section
5539: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5540: . point - The mesh point
5541: . numIndices - The number of indices
5542: . indices - The indices
5543: - outOffsets - Field offset if not NULL

5545:   Level: advanced

5547: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5548: @*/
5549: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5550: {

5556:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5557:   return(0);
5558: }

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

5563:   Not collective

5565:   Input Parameters:
5566: + dm - The DM
5567: . section - The section describing the layout in v, or NULL to use the default section
5568: . globalSection - The section describing the layout in v, or NULL to use the default global section
5569: . A - The matrix
5570: . point - The point in the DM
5571: . values - The array of values
5572: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5577:   Level: intermediate

5579: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5580: @*/
5581: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5582: {
5583:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5584:   PetscSection        clSection;
5585:   IS                  clPoints;
5586:   PetscInt           *points = NULL, *newPoints;
5587:   const PetscInt     *clp;
5588:   PetscInt           *indices;
5589:   PetscInt            offsets[32];
5590:   const PetscInt    **perms[32] = {NULL};
5591:   const PetscScalar **flips[32] = {NULL};
5592:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5593:   PetscScalar        *valCopy = NULL;
5594:   PetscScalar        *newValues;
5595:   PetscErrorCode      ierr;

5599:   if (!section) {DMGetDefaultSection(dm, &section);}
5601:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5604:   PetscSectionGetNumFields(section, &numFields);
5605:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5606:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5607:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5608:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5609:     PetscInt fdof;

5611:     PetscSectionGetDof(section, points[p], &dof);
5612:     for (f = 0; f < numFields; ++f) {
5613:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5614:       offsets[f+1] += fdof;
5615:     }
5616:     numIndices += dof;
5617:   }
5618:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5632:         if (!numFields) {
5633:           PetscSectionGetDof(section,point,&fdof);
5634:         } else {
5635:           PetscSectionGetFieldDof(section,point,f,&fdof);
5636:         }
5637:         if (flip) {
5638:           PetscInt i, j, k;

5640:           if (!valCopy) {
5641:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5642:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5643:             values = valCopy;
5644:           }
5645:           for (i = 0; i < fdof; i++) {
5646:             PetscScalar fval = flip[i];

5648:             for (k = 0; k < numIndices; k++) {
5649:               valCopy[numIndices * (foffset + i) + k] *= fval;
5650:               valCopy[numIndices * k + (foffset + i)] *= fval;
5651:             }
5652:           }
5653:         }
5654:         foffset += fdof;
5655:       }
5656:     }
5657:   }
5658:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5659:   if (newNumPoints) {
5660:     if (valCopy) {
5661:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5662:     }
5663:     for (f = 0; f < PetscMax(1,numFields); f++) {
5664:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5665:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5666:     }
5667:     for (f = 0; f < PetscMax(1,numFields); f++) {
5668:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5669:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5670:     }
5671:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5672:     numPoints  = newNumPoints;
5673:     numIndices = newNumIndices;
5674:     points     = newPoints;
5675:     values     = newValues;
5676:   }
5677:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5678:   if (numFields) {
5679:     for (p = 0; p < numPoints; p++) {
5680:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5681:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5682:     }
5683:   } else {
5684:     for (p = 0, off = 0; p < numPoints; p++) {
5685:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5686:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5687:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5688:     }
5689:   }
5690:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5691:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5692:   if (mesh->printFEM > 1) {
5693:     PetscInt i;
5694:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5695:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5696:     PetscPrintf(PETSC_COMM_SELF, "\n");
5697:   }
5698:   if (ierr) {
5699:     PetscMPIInt    rank;
5700:     PetscErrorCode ierr2;

5702:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5703:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5704:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5705:     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5706: 
5707:   }
5708:   for (f = 0; f < PetscMax(1,numFields); f++) {
5709:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5710:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5711:   }
5712:   if (newNumPoints) {
5713:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5714:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5715:   }
5716:   else {
5717:     if (valCopy) {
5718:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5719:     }
5720:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5721:   }
5722:   DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
5723:   return(0);
5724: }

5726: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5727: {
5728:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5729:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5730:   PetscInt       *cpoints = NULL;
5731:   PetscInt       *findices, *cindices;
5732:   PetscInt        foffsets[32], coffsets[32];
5733:   CellRefiner     cellRefiner;
5734:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5735:   PetscErrorCode  ierr;

5740:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5742:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5744:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5746:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5749:   PetscSectionGetNumFields(fsection, &numFields);
5750:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5751:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5752:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5753:   /* Column indices */
5754:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5755:   maxFPoints = numCPoints;
5756:   /* Compress out points not in the section */
5757:   /*   TODO: Squeeze out points with 0 dof as well */
5758:   PetscSectionGetChart(csection, &pStart, &pEnd);
5759:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5760:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5761:       cpoints[q*2]   = cpoints[p];
5762:       cpoints[q*2+1] = cpoints[p+1];
5763:       ++q;
5764:     }
5765:   }
5766:   numCPoints = q;
5767:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5768:     PetscInt fdof;

5770:     PetscSectionGetDof(csection, cpoints[p], &dof);
5771:     if (!dof) continue;
5772:     for (f = 0; f < numFields; ++f) {
5773:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5774:       coffsets[f+1] += fdof;
5775:     }
5776:     numCIndices += dof;
5777:   }
5778:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5779:   /* Row indices */
5780:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5781:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5782:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5783:   for (r = 0, q = 0; r < numSubcells; ++r) {
5784:     /* TODO Map from coarse to fine cells */
5785:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5786:     /* Compress out points not in the section */
5787:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5788:     for (p = 0; p < numFPoints*2; p += 2) {
5789:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5790:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5791:         if (!dof) continue;
5792:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5793:         if (s < q) continue;
5794:         ftotpoints[q*2]   = fpoints[p];
5795:         ftotpoints[q*2+1] = fpoints[p+1];
5796:         ++q;
5797:       }
5798:     }
5799:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5800:   }
5801:   numFPoints = q;
5802:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5803:     PetscInt fdof;

5805:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5806:     if (!dof) continue;
5807:     for (f = 0; f < numFields; ++f) {
5808:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5809:       foffsets[f+1] += fdof;
5810:     }
5811:     numFIndices += dof;
5812:   }
5813:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5815:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5816:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5817:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5818:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5819:   if (numFields) {
5820:     const PetscInt **permsF[32] = {NULL};
5821:     const PetscInt **permsC[32] = {NULL};

5823:     for (f = 0; f < numFields; f++) {
5824:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5825:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5826:     }
5827:     for (p = 0; p < numFPoints; p++) {
5828:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5829:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5830:     }
5831:     for (p = 0; p < numCPoints; p++) {
5832:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5833:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5834:     }
5835:     for (f = 0; f < numFields; f++) {
5836:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5837:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5838:     }
5839:   } else {
5840:     const PetscInt **permsF = NULL;
5841:     const PetscInt **permsC = NULL;

5843:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5844:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5845:     for (p = 0, off = 0; p < numFPoints; p++) {
5846:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5848:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5849:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5850:     }
5851:     for (p = 0, off = 0; p < numCPoints; p++) {
5852:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5854:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5855:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5856:     }
5857:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5858:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5859:   }
5860:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5861:   /* TODO: flips */
5862:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5863:   if (ierr) {
5864:     PetscMPIInt    rank;
5865:     PetscErrorCode ierr2;

5867:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5868:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5869:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5870:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
5871:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
5872: 
5873:   }
5874:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
5875:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5876:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5877:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5878:   return(0);
5879: }

5881: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5882: {
5883:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5884:   PetscInt      *cpoints = NULL;
5885:   PetscInt       foffsets[32], coffsets[32];
5886:   CellRefiner    cellRefiner;
5887:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

5893:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5895:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5897:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5899:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5901:   PetscSectionGetNumFields(fsection, &numFields);
5902:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5903:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5904:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5905:   /* Column indices */
5906:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5907:   maxFPoints = numCPoints;
5908:   /* Compress out points not in the section */
5909:   /*   TODO: Squeeze out points with 0 dof as well */
5910:   PetscSectionGetChart(csection, &pStart, &pEnd);
5911:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5912:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5913:       cpoints[q*2]   = cpoints[p];
5914:       cpoints[q*2+1] = cpoints[p+1];
5915:       ++q;
5916:     }
5917:   }
5918:   numCPoints = q;
5919:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5920:     PetscInt fdof;

5922:     PetscSectionGetDof(csection, cpoints[p], &dof);
5923:     if (!dof) continue;
5924:     for (f = 0; f < numFields; ++f) {
5925:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5926:       coffsets[f+1] += fdof;
5927:     }
5928:     numCIndices += dof;
5929:   }
5930:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5931:   /* Row indices */
5932:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5933:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5934:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5935:   for (r = 0, q = 0; r < numSubcells; ++r) {
5936:     /* TODO Map from coarse to fine cells */
5937:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5938:     /* Compress out points not in the section */
5939:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5940:     for (p = 0; p < numFPoints*2; p += 2) {
5941:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5942:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5943:         if (!dof) continue;
5944:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5945:         if (s < q) continue;
5946:         ftotpoints[q*2]   = fpoints[p];
5947:         ftotpoints[q*2+1] = fpoints[p+1];
5948:         ++q;
5949:       }
5950:     }
5951:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5952:   }
5953:   numFPoints = q;
5954:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5955:     PetscInt fdof;

5957:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5958:     if (!dof) continue;
5959:     for (f = 0; f < numFields; ++f) {
5960:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5961:       foffsets[f+1] += fdof;
5962:     }
5963:     numFIndices += dof;
5964:   }
5965:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

5973:     for (f = 0; f < numFields; f++) {
5974:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5975:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5976:     }
5977:     for (p = 0; p < numFPoints; p++) {
5978:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5979:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5980:     }
5981:     for (p = 0; p < numCPoints; p++) {
5982:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5983:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5984:     }
5985:     for (f = 0; f < numFields; f++) {
5986:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5987:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5988:     }
5989:   } else {
5990:     const PetscInt **permsF = NULL;
5991:     const PetscInt **permsC = NULL;

5993:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5994:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5995:     for (p = 0, off = 0; p < numFPoints; p++) {
5996:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5998:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5999:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
6000:     }
6001:     for (p = 0, off = 0; p < numCPoints; p++) {
6002:       const PetscInt *perm = permsC ? permsC[p] : NULL;

6004:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
6005:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
6006:     }
6007:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
6008:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
6009:   }
6010:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
6011:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
6012:   return(0);
6013: }

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

6018:   Input Parameter:
6019: . dm - The DMPlex object

6021:   Output Parameters:
6022: + cMax - The first hybrid cell
6023: . fMax - The first hybrid face
6024: . eMax - The first hybrid edge
6025: - vMax - The first hybrid vertex

6027:   Level: developer

6029: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6030: @*/
6031: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6032: {
6033:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6034:   PetscInt       dim;

6039:   DMGetDimension(dm, &dim);
6040:   if (cMax) *cMax = mesh->hybridPointMax[dim];
6041:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
6042:   if (eMax) *eMax = mesh->hybridPointMax[1];
6043:   if (vMax) *vMax = mesh->hybridPointMax[0];
6044:   return(0);
6045: }

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

6050:   Input Parameters:
6051: . dm   - The DMPlex object
6052: . cMax - The first hybrid cell
6053: . fMax - The first hybrid face
6054: . eMax - The first hybrid edge
6055: - vMax - The first hybrid vertex

6057:   Level: developer

6059: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6060: @*/
6061: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6062: {
6063:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6064:   PetscInt       dim;

6069:   DMGetDimension(dm, &dim);
6070:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
6071:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
6072:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
6073:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
6074:   return(0);
6075: }

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

6080:   Input Parameter:
6081: . dm   - The DMPlex object

6083:   Output Parameter:
6084: . cellHeight - The height of a cell

6086:   Level: developer

6088: .seealso DMPlexSetVTKCellHeight()
6089: @*/
6090: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6091: {
6092:   DM_Plex *mesh = (DM_Plex*) dm->data;

6097:   *cellHeight = mesh->vtkCellHeight;
6098:   return(0);
6099: }

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

6104:   Input Parameters:
6105: + dm   - The DMPlex object
6106: - cellHeight - The height of a cell

6108:   Level: developer

6110: .seealso DMPlexGetVTKCellHeight()
6111: @*/
6112: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6113: {
6114:   DM_Plex *mesh = (DM_Plex*) dm->data;

6118:   mesh->vtkCellHeight = cellHeight;
6119:   return(0);
6120: }

6122: /* We can easily have a form that takes an IS instead */
6123: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6124: {
6125:   PetscSection   section, globalSection;
6126:   PetscInt      *numbers, p;

6130:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6131:   PetscSectionSetChart(section, pStart, pEnd);
6132:   for (p = pStart; p < pEnd; ++p) {
6133:     PetscSectionSetDof(section, p, 1);
6134:   }
6135:   PetscSectionSetUp(section);
6136:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6137:   PetscMalloc1(pEnd - pStart, &numbers);
6138:   for (p = pStart; p < pEnd; ++p) {
6139:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6140:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6141:     else                       numbers[p-pStart] += shift;
6142:   }
6143:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6144:   if (globalSize) {
6145:     PetscLayout layout;
6146:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6147:     PetscLayoutGetSize(layout, globalSize);
6148:     PetscLayoutDestroy(&layout);
6149:   }
6150:   PetscSectionDestroy(&section);
6151:   PetscSectionDestroy(&globalSection);
6152:   return(0);
6153: }

6155: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6156: {
6157:   PetscInt       cellHeight, cStart, cEnd, cMax;

6161:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6162:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6163:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6164:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6165:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6166:   return(0);
6167: }

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

6172:   Input Parameter:
6173: . dm   - The DMPlex object

6175:   Output Parameter:
6176: . globalCellNumbers - Global cell numbers for all cells on this process

6178:   Level: developer

6180: .seealso DMPlexGetVertexNumbering()
6181: @*/
6182: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6183: {
6184:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6189:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6190:   *globalCellNumbers = mesh->globalCellNumbers;
6191:   return(0);
6192: }

6194: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6195: {
6196:   PetscInt       vStart, vEnd, vMax;

6201:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6202:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6203:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6204:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6205:   return(0);
6206: }

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

6211:   Input Parameter:
6212: . dm   - The DMPlex object

6214:   Output Parameter:
6215: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6217:   Level: developer

6219: .seealso DMPlexGetCellNumbering()
6220: @*/
6221: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6222: {
6223:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6228:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6229:   *globalVertexNumbers = mesh->globalVertexNumbers;
6230:   return(0);
6231: }

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

6236:   Input Parameter:
6237: . dm   - The DMPlex object

6239:   Output Parameter:
6240: . globalPointNumbers - Global numbers for all points on this process

6242:   Level: developer

6244: .seealso DMPlexGetCellNumbering()
6245: @*/
6246: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6247: {
6248:   IS             nums[4];
6249:   PetscInt       depths[4];
6250:   PetscInt       depth, d, shift = 0;

6255:   DMPlexGetDepth(dm, &depth);
6256:   /* For unstratified meshes use dim instead of depth */
6257:   if (depth < 0) {DMGetDimension(dm, &depth);}
6258:   depths[0] = depth; depths[1] = 0;
6259:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6260:   for (d = 0; d <= depth; ++d) {
6261:     PetscInt pStart, pEnd, gsize;

6263:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6264:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6265:     shift += gsize;
6266:   }
6267:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6268:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6269:   return(0);
6270: }


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

6276:   Input Parameter:
6277: . dm - The DMPlex object

6279:   Output Parameter:
6280: . ranks - The rank field

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

6285:   Level: intermediate

6287: .seealso: DMView()
6288: @*/
6289: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6290: {
6291:   DM             rdm;
6292:   PetscDS        prob;
6293:   PetscFE        fe;
6294:   PetscScalar   *r;
6295:   PetscMPIInt    rank;
6296:   PetscInt       dim, cStart, cEnd, c;

6300:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6301:   DMClone(dm, &rdm);
6302:   DMGetDimension(rdm, &dim);
6303:   PetscFECreateDefault(rdm, dim, 1, PETSC_TRUE, NULL, -1, &fe);
6304:   PetscObjectSetName((PetscObject) fe, "rank");
6305:   DMGetDS(rdm, &prob);
6306:   PetscDSSetDiscretization(prob, 0, (PetscObject) fe);
6307:   PetscFEDestroy(&fe);
6308:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6309:   DMCreateGlobalVector(rdm, ranks);
6310:   PetscObjectSetName((PetscObject) *ranks, "partition");
6311:   VecGetArray(*ranks, &r);
6312:   for (c = cStart; c < cEnd; ++c) {
6313:     PetscScalar *lr;

6315:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6316:     *lr = rank;
6317:   }
6318:   VecRestoreArray(*ranks, &r);
6319:   DMDestroy(&rdm);
6320:   return(0);
6321: }

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

6326:   Input Parameter:
6327: . dm - The DMPlex object

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

6331:   Level: developer

6333: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6334: @*/
6335: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6336: {
6337:   PetscSection    coneSection, supportSection;
6338:   const PetscInt *cone, *support;
6339:   PetscInt        coneSize, c, supportSize, s;
6340:   PetscInt        pStart, pEnd, p, csize, ssize;
6341:   PetscErrorCode  ierr;

6345:   DMPlexGetConeSection(dm, &coneSection);
6346:   DMPlexGetSupportSection(dm, &supportSection);
6347:   /* Check that point p is found in the support of its cone points, and vice versa */
6348:   DMPlexGetChart(dm, &pStart, &pEnd);
6349:   for (p = pStart; p < pEnd; ++p) {
6350:     DMPlexGetConeSize(dm, p, &coneSize);
6351:     DMPlexGetCone(dm, p, &cone);
6352:     for (c = 0; c < coneSize; ++c) {
6353:       PetscBool dup = PETSC_FALSE;
6354:       PetscInt  d;
6355:       for (d = c-1; d >= 0; --d) {
6356:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6357:       }
6358:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6359:       DMPlexGetSupport(dm, cone[c], &support);
6360:       for (s = 0; s < supportSize; ++s) {
6361:         if (support[s] == p) break;
6362:       }
6363:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6364:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6365:         for (s = 0; s < coneSize; ++s) {
6366:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6367:         }
6368:         PetscPrintf(PETSC_COMM_SELF, "\n");
6369:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6370:         for (s = 0; s < supportSize; ++s) {
6371:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6372:         }
6373:         PetscPrintf(PETSC_COMM_SELF, "\n");
6374:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6375:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6376:       }
6377:     }
6378:     DMPlexGetSupportSize(dm, p, &supportSize);
6379:     DMPlexGetSupport(dm, p, &support);
6380:     for (s = 0; s < supportSize; ++s) {
6381:       DMPlexGetConeSize(dm, support[s], &coneSize);
6382:       DMPlexGetCone(dm, support[s], &cone);
6383:       for (c = 0; c < coneSize; ++c) {
6384:         if (cone[c] == p) break;
6385:       }
6386:       if (c >= coneSize) {
6387:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6388:         for (c = 0; c < supportSize; ++c) {
6389:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6390:         }
6391:         PetscPrintf(PETSC_COMM_SELF, "\n");
6392:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6393:         for (c = 0; c < coneSize; ++c) {
6394:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6395:         }
6396:         PetscPrintf(PETSC_COMM_SELF, "\n");
6397:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6398:       }
6399:     }
6400:   }
6401:   PetscSectionGetStorageSize(coneSection, &csize);
6402:   PetscSectionGetStorageSize(supportSection, &ssize);
6403:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6404:   return(0);
6405: }

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

6410:   Input Parameters:
6411: + dm - The DMPlex object
6412: . isSimplex - Are the cells simplices or tensor products
6413: - cellHeight - Normally 0

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

6417:   Level: developer

6419: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6420: @*/
6421: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6422: {
6423:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6428:   DMGetDimension(dm, &dim);
6429:   switch (dim) {
6430:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6431:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6432:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6433:   default:
6434:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6435:   }
6436:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6437:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6438:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6439:   cMax = cMax >= 0 ? cMax : cEnd;
6440:   for (c = cStart; c < cMax; ++c) {
6441:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6443:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6444:     for (cl = 0; cl < closureSize*2; cl += 2) {
6445:       const PetscInt p = closure[cl];
6446:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6447:     }
6448:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6449:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6450:   }
6451:   for (c = cMax; c < cEnd; ++c) {
6452:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6454:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6455:     for (cl = 0; cl < closureSize*2; cl += 2) {
6456:       const PetscInt p = closure[cl];
6457:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6458:     }
6459:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6460:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6461:   }
6462:   return(0);
6463: }

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

6468:   Input Parameters:
6469: + dm - The DMPlex object
6470: . isSimplex - Are the cells simplices or tensor products
6471: - cellHeight - Normally 0

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

6475:   Level: developer

6477: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6478: @*/
6479: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6480: {
6481:   PetscInt       pMax[4];
6482:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

6487:   DMGetDimension(dm, &dim);
6488:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6489:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6490:   for (h = cellHeight; h < dim; ++h) {
6491:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6492:     for (c = cStart; c < cEnd; ++c) {
6493:       const PetscInt *cone, *ornt, *faces;
6494:       PetscInt        numFaces, faceSize, coneSize,f;
6495:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6497:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6498:       DMPlexGetConeSize(dm, c, &coneSize);
6499:       DMPlexGetCone(dm, c, &cone);
6500:       DMPlexGetConeOrientation(dm, c, &ornt);
6501:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6502:       for (cl = 0; cl < closureSize*2; cl += 2) {
6503:         const PetscInt p = closure[cl];
6504:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6505:       }
6506:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6507:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6508:       for (f = 0; f < numFaces; ++f) {
6509:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6511:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6512:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6513:           const PetscInt p = fclosure[cl];
6514:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6515:         }
6516:         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);
6517:         for (v = 0; v < fnumCorners; ++v) {
6518:           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]);
6519:         }
6520:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6521:       }
6522:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6523:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6524:     }
6525:   }
6526:   return(0);
6527: }

6529: /* Pointwise interpolation
6530:      Just code FEM for now
6531:      u^f = I u^c
6532:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6533:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6534:      I_{ij} = psi^f_i phi^c_j
6535: */
6536: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6537: {
6538:   PetscSection   gsc, gsf;
6539:   PetscInt       m, n;
6540:   void          *ctx;
6541:   DM             cdm;
6542:   PetscBool      regular;

6546:   DMGetDefaultGlobalSection(dmFine, &gsf);
6547:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6548:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6549:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6551:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6552:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6553:   MatSetType(*interpolation, dmCoarse->mattype);
6554:   DMGetApplicationContext(dmFine, &ctx);

6556:   DMGetCoarseDM(dmFine, &cdm);
6557:   DMPlexGetRegularRefinement(dmFine, &regular);
6558:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6559:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6560:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6561:   /* Use naive scaling */
6562:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6563:   return(0);
6564: }

6566: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6567: {
6569:   VecScatter     ctx;

6572:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6573:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6574:   VecScatterDestroy(&ctx);
6575:   return(0);
6576: }

6578: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6579: {
6580:   PetscSection   gsc, gsf;
6581:   PetscInt       m, n;
6582:   void          *ctx;
6583:   DM             cdm;
6584:   PetscBool      regular;

6588:   DMGetDefaultGlobalSection(dmFine, &gsf);
6589:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6590:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6591:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6593:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
6594:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6595:   MatSetType(*mass, dmCoarse->mattype);
6596:   DMGetApplicationContext(dmFine, &ctx);

6598:   DMGetCoarseDM(dmFine, &cdm);
6599:   DMPlexGetRegularRefinement(dmFine, &regular);
6600:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
6601:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
6602:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
6603:   return(0);
6604: }

6606: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6607: {
6608:   PetscSection   section;
6609:   IS            *bcPoints, *bcComps;
6610:   PetscBool     *isFE;
6611:   PetscInt      *bcFields, *numComp, *numDof;
6612:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6613:   PetscInt       cStart, cEnd, cEndInterior;

6617:   DMGetNumFields(dm, &numFields);
6618:   /* FE and FV boundary conditions are handled slightly differently */
6619:   PetscMalloc1(numFields, &isFE);
6620:   for (f = 0; f < numFields; ++f) {
6621:     PetscObject  obj;
6622:     PetscClassId id;

6624:     DMGetField(dm, f, &obj);
6625:     PetscObjectGetClassId(obj, &id);
6626:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6627:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6628:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6629:   }
6630:   /* Allocate boundary point storage for FEM boundaries */
6631:   DMPlexGetDepth(dm, &depth);
6632:   DMGetDimension(dm, &dim);
6633:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6634:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6635:   PetscDSGetNumBoundary(dm->prob, &numBd);
6636:   if (!numFields && numBd) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "number of fields is zero and number of boundary conditions is nonzero (this should never happen)");
6637:   for (bd = 0; bd < numBd; ++bd) {
6638:     PetscInt                field;
6639:     DMBoundaryConditionType type;
6640:     const char             *labelName;
6641:     DMLabel                 label;

6643:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6644:     DMGetLabel(dm,labelName,&label);
6645:     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6646:   }
6647:   /* Add ghost cell boundaries for FVM */
6648:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6649:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6650:   /* Constrain ghost cells for FV */
6651:   for (f = 0; f < numFields; ++f) {
6652:     PetscInt *newidx, c;

6654:     if (isFE[f] || cEndInterior < 0) continue;
6655:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6656:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6657:     bcFields[bc] = f;
6658:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6659:   }
6660:   /* Handle FEM Dirichlet boundaries */
6661:   for (bd = 0; bd < numBd; ++bd) {
6662:     const char             *bdLabel;
6663:     DMLabel                 label;
6664:     const PetscInt         *comps;
6665:     const PetscInt         *values;
6666:     PetscInt                bd2, field, numComps, numValues;
6667:     DMBoundaryConditionType type;
6668:     PetscBool               duplicate = PETSC_FALSE;

6670:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6671:     DMGetLabel(dm, bdLabel, &label);
6672:     if (!isFE[field] || !label) continue;
6673:     /* Only want to modify label once */
6674:     for (bd2 = 0; bd2 < bd; ++bd2) {
6675:       const char *bdname;
6676:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6677:       PetscStrcmp(bdname, bdLabel, &duplicate);
6678:       if (duplicate) break;
6679:     }
6680:     if (!duplicate && (isFE[field])) {
6681:       /* don't complete cells, which are just present to give orientation to the boundary */
6682:       DMPlexLabelComplete(dm, label);
6683:     }
6684:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6685:     if (type & DM_BC_ESSENTIAL) {
6686:       PetscInt       *newidx;
6687:       PetscInt        n, newn = 0, p, v;

6689:       bcFields[bc] = field;
6690:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6691:       for (v = 0; v < numValues; ++v) {
6692:         IS              tmp;
6693:         const PetscInt *idx;

6695:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6696:         if (!tmp) continue;
6697:         ISGetLocalSize(tmp, &n);
6698:         ISGetIndices(tmp, &idx);
6699:         if (isFE[field]) {
6700:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6701:         } else {
6702:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6703:         }
6704:         ISRestoreIndices(tmp, &idx);
6705:         ISDestroy(&tmp);
6706:       }
6707:       PetscMalloc1(newn,&newidx);
6708:       newn = 0;
6709:       for (v = 0; v < numValues; ++v) {
6710:         IS              tmp;
6711:         const PetscInt *idx;

6713:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6714:         if (!tmp) continue;
6715:         ISGetLocalSize(tmp, &n);
6716:         ISGetIndices(tmp, &idx);
6717:         if (isFE[field]) {
6718:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6719:         } else {
6720:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6721:         }
6722:         ISRestoreIndices(tmp, &idx);
6723:         ISDestroy(&tmp);
6724:       }
6725:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6726:     }
6727:   }
6728:   /* Handle discretization */
6729:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6730:   for (f = 0; f < numFields; ++f) {
6731:     PetscObject obj;

6733:     DMGetField(dm, f, &obj);
6734:     if (isFE[f]) {
6735:       PetscFE         fe = (PetscFE) obj;
6736:       const PetscInt *numFieldDof;
6737:       PetscInt        d;

6739:       PetscFEGetNumComponents(fe, &numComp[f]);
6740:       PetscFEGetNumDof(fe, &numFieldDof);
6741:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6742:     } else {
6743:       PetscFV fv = (PetscFV) obj;

6745:       PetscFVGetNumComponents(fv, &numComp[f]);
6746:       numDof[f*(dim+1)+dim] = numComp[f];
6747:     }
6748:   }
6749:   for (f = 0; f < numFields; ++f) {
6750:     PetscInt d;
6751:     for (d = 1; d < dim; ++d) {
6752:       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.");
6753:     }
6754:   }
6755:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6756:   for (f = 0; f < numFields; ++f) {
6757:     PetscFE     fe;
6758:     const char *name;

6760:     DMGetField(dm, f, (PetscObject *) &fe);
6761:     PetscObjectGetName((PetscObject) fe, &name);
6762:     PetscSectionSetFieldName(section, f, name);
6763:   }
6764:   DMSetDefaultSection(dm, section);
6765:   PetscSectionDestroy(&section);
6766:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6767:   PetscFree3(bcFields,bcPoints,bcComps);
6768:   PetscFree2(numComp,numDof);
6769:   PetscFree(isFE);
6770:   return(0);
6771: }

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

6776:   Input Parameter:
6777: . dm - The DMPlex object

6779:   Output Parameter:
6780: . regular - The flag

6782:   Level: intermediate

6784: .seealso: DMPlexSetRegularRefinement()
6785: @*/
6786: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6787: {
6791:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6792:   return(0);
6793: }

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

6798:   Input Parameters:
6799: + dm - The DMPlex object
6800: - regular - The flag

6802:   Level: intermediate

6804: .seealso: DMPlexGetRegularRefinement()
6805: @*/
6806: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6807: {
6810:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6811:   return(0);
6812: }

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

6819:   not collective

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

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


6829:   Level: intermediate

6831: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6832: @*/
6833: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6834: {
6835:   DM_Plex *plex = (DM_Plex *)dm->data;

6840:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6841:   if (anchorSection) *anchorSection = plex->anchorSection;
6842:   if (anchorIS) *anchorIS = plex->anchorIS;
6843:   return(0);
6844: }

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

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

6854:   collective on dm

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

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

6863:   Level: intermediate

6865: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6866: @*/
6867: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6868: {
6869:   DM_Plex        *plex = (DM_Plex *)dm->data;
6870:   PetscMPIInt    result;

6875:   if (anchorSection) {
6877:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6878:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6879:   }
6880:   if (anchorIS) {
6882:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6883:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6884:   }

6886:   PetscObjectReference((PetscObject)anchorSection);
6887:   PetscSectionDestroy(&plex->anchorSection);
6888:   plex->anchorSection = anchorSection;

6890:   PetscObjectReference((PetscObject)anchorIS);
6891:   ISDestroy(&plex->anchorIS);
6892:   plex->anchorIS = anchorIS;

6894: #if defined(PETSC_USE_DEBUG)
6895:   if (anchorIS && anchorSection) {
6896:     PetscInt size, a, pStart, pEnd;
6897:     const PetscInt *anchors;

6899:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6900:     ISGetLocalSize(anchorIS,&size);
6901:     ISGetIndices(anchorIS,&anchors);
6902:     for (a = 0; a < size; a++) {
6903:       PetscInt p;

6905:       p = anchors[a];
6906:       if (p >= pStart && p < pEnd) {
6907:         PetscInt dof;

6909:         PetscSectionGetDof(anchorSection,p,&dof);
6910:         if (dof) {
6911:           PetscErrorCode ierr2;

6913:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6914:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6915:         }
6916:       }
6917:     }
6918:     ISRestoreIndices(anchorIS,&anchors);
6919:   }
6920: #endif
6921:   /* reset the generic constraints */
6922:   DMSetDefaultConstraints(dm,NULL,NULL);
6923:   return(0);
6924: }

6926: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6927: {
6928:   PetscSection anchorSection;
6929:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

6934:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6935:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6936:   PetscSectionGetNumFields(section,&numFields);
6937:   if (numFields) {
6938:     PetscInt f;
6939:     PetscSectionSetNumFields(*cSec,numFields);

6941:     for (f = 0; f < numFields; f++) {
6942:       PetscInt numComp;

6944:       PetscSectionGetFieldComponents(section,f,&numComp);
6945:       PetscSectionSetFieldComponents(*cSec,f,numComp);
6946:     }
6947:   }
6948:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6949:   PetscSectionGetChart(section,&sStart,&sEnd);
6950:   pStart = PetscMax(pStart,sStart);
6951:   pEnd   = PetscMin(pEnd,sEnd);
6952:   pEnd   = PetscMax(pStart,pEnd);
6953:   PetscSectionSetChart(*cSec,pStart,pEnd);
6954:   for (p = pStart; p < pEnd; p++) {
6955:     PetscSectionGetDof(anchorSection,p,&dof);
6956:     if (dof) {
6957:       PetscSectionGetDof(section,p,&dof);
6958:       PetscSectionSetDof(*cSec,p,dof);
6959:       for (f = 0; f < numFields; f++) {
6960:         PetscSectionGetFieldDof(section,p,f,&dof);
6961:         PetscSectionSetFieldDof(*cSec,p,f,dof);
6962:       }
6963:     }
6964:   }
6965:   PetscSectionSetUp(*cSec);
6966:   return(0);
6967: }

6969: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6970: {
6971:   PetscSection aSec;
6972:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6973:   const PetscInt *anchors;
6974:   PetscInt numFields, f;
6975:   IS aIS;

6980:   PetscSectionGetStorageSize(cSec, &m);
6981:   PetscSectionGetStorageSize(section, &n);
6982:   MatCreate(PETSC_COMM_SELF,cMat);
6983:   MatSetSizes(*cMat,m,n,m,n);
6984:   MatSetType(*cMat,MATSEQAIJ);
6985:   DMPlexGetAnchors(dm,&aSec,&aIS);
6986:   ISGetIndices(aIS,&anchors);
6987:   /* cSec will be a subset of aSec and section */
6988:   PetscSectionGetChart(cSec,&pStart,&pEnd);
6989:   PetscMalloc1(m+1,&i);
6990:   i[0] = 0;
6991:   PetscSectionGetNumFields(section,&numFields);
6992:   for (p = pStart; p < pEnd; p++) {
6993:     PetscInt rDof, rOff, r;

6995:     PetscSectionGetDof(aSec,p,&rDof);
6996:     if (!rDof) continue;
6997:     PetscSectionGetOffset(aSec,p,&rOff);
6998:     if (numFields) {
6999:       for (f = 0; f < numFields; f++) {
7000:         annz = 0;
7001:         for (r = 0; r < rDof; r++) {
7002:           a = anchors[rOff + r];
7003:           PetscSectionGetFieldDof(section,a,f,&aDof);
7004:           annz += aDof;
7005:         }
7006:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7007:         PetscSectionGetFieldOffset(cSec,p,f,&off);
7008:         for (q = 0; q < dof; q++) {
7009:           i[off + q + 1] = i[off + q] + annz;
7010:         }
7011:       }
7012:     }
7013:     else {
7014:       annz = 0;
7015:       for (q = 0; q < dof; q++) {
7016:         a = anchors[off + q];
7017:         PetscSectionGetDof(section,a,&aDof);
7018:         annz += aDof;
7019:       }
7020:       PetscSectionGetDof(cSec,p,&dof);
7021:       PetscSectionGetOffset(cSec,p,&off);
7022:       for (q = 0; q < dof; q++) {
7023:         i[off + q + 1] = i[off + q] + annz;
7024:       }
7025:     }
7026:   }
7027:   nnz = i[m];
7028:   PetscMalloc1(nnz,&j);
7029:   offset = 0;
7030:   for (p = pStart; p < pEnd; p++) {
7031:     if (numFields) {
7032:       for (f = 0; f < numFields; f++) {
7033:         PetscSectionGetFieldDof(cSec,p,f,&dof);
7034:         for (q = 0; q < dof; q++) {
7035:           PetscInt rDof, rOff, r;
7036:           PetscSectionGetDof(aSec,p,&rDof);
7037:           PetscSectionGetOffset(aSec,p,&rOff);
7038:           for (r = 0; r < rDof; r++) {
7039:             PetscInt s;

7041:             a = anchors[rOff + r];
7042:             PetscSectionGetFieldDof(section,a,f,&aDof);
7043:             PetscSectionGetFieldOffset(section,a,f,&aOff);
7044:             for (s = 0; s < aDof; s++) {
7045:               j[offset++] = aOff + s;
7046:             }
7047:           }
7048:         }
7049:       }
7050:     }
7051:     else {
7052:       PetscSectionGetDof(cSec,p,&dof);
7053:       for (q = 0; q < dof; q++) {
7054:         PetscInt rDof, rOff, r;
7055:         PetscSectionGetDof(aSec,p,&rDof);
7056:         PetscSectionGetOffset(aSec,p,&rOff);
7057:         for (r = 0; r < rDof; r++) {
7058:           PetscInt s;

7060:           a = anchors[rOff + r];
7061:           PetscSectionGetDof(section,a,&aDof);
7062:           PetscSectionGetOffset(section,a,&aOff);
7063:           for (s = 0; s < aDof; s++) {
7064:             j[offset++] = aOff + s;
7065:           }
7066:         }
7067:       }
7068:     }
7069:   }
7070:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7071:   PetscFree(i);
7072:   PetscFree(j);
7073:   ISRestoreIndices(aIS,&anchors);
7074:   return(0);
7075: }

7077: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7078: {
7079:   DM_Plex        *plex = (DM_Plex *)dm->data;
7080:   PetscSection   anchorSection, section, cSec;
7081:   Mat            cMat;

7086:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7087:   if (anchorSection) {
7088:     PetscDS  ds;
7089:     PetscInt nf;

7091:     DMGetDefaultSection(dm,&section);
7092:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7093:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7094:     DMGetDS(dm,&ds);
7095:     PetscDSGetNumFields(ds,&nf);
7096:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7097:     DMSetDefaultConstraints(dm,cSec,cMat);
7098:     PetscSectionDestroy(&cSec);
7099:     MatDestroy(&cMat);
7100:   }
7101:   return(0);
7102: }