Actual source code: plex.c

petsc-master 2018-01-20
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, vdof = 0, cdof = 0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

284:     DMGetNumFields(dm, &numFields);
285:     if (numFields) {
286:       PetscObject fe;

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

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

319: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
320: {
321:   DM             dm;
322:   PetscReal      time = 0.0;
323:   PetscBool      isvtk, ishdf5, isdraw, isseq, isglvis;

327:   VecGetDM(v, &dm);
328:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
329:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
330:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
331:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
332:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
333:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
334:   PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
335:   if (isvtk || isglvis) {
336:     PetscInt    num;
337:     Vec         locv;
338:     const char *name;

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

360:     DMGetLocalVector(dm, &locv);
361:     PetscObjectGetName((PetscObject) v, &name);
362:     PetscObjectSetName((PetscObject) locv, name);
363:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
364:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
365:     DMGetOutputSequenceNumber(dm, NULL, &time);
366:     DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);
367:     VecView_Plex_Local(locv, viewer);
368:     DMRestoreLocalVector(dm, &locv);
369:   } else {
370:     if (isseq) {VecView_Seq(v, viewer);}
371:     else       {VecView_MPI(v, viewer);}
372:   }
373:   return(0);
374: }

376: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
377: {
378:   DM                dm;
379:   MPI_Comm          comm;
380:   PetscViewerFormat format;
381:   Vec               v;
382:   PetscBool         isvtk, ishdf5;
383:   PetscErrorCode    ierr;

386:   VecGetDM(originalv, &dm);
387:   PetscObjectGetComm((PetscObject) originalv, &comm);
388:   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
389:   PetscViewerGetFormat(viewer, &format);
390:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
391:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);
392:   if (format == PETSC_VIEWER_NATIVE) {
393:     const char *vecname;
394:     PetscInt    n, nroots;

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

422:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
423:     if (isseq) {VecView_Seq(v, viewer);}
424:     else       {VecView_MPI(v, viewer);}
425:   }
426:   if (format == PETSC_VIEWER_NATIVE) {DMRestoreGlobalVector(dm, &v);}
427:   return(0);
428: }

430: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
431: {
432:   DM             dm;
433:   PetscBool      ishdf5;

437:   VecGetDM(v, &dm);
438:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
439:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
440:   if (ishdf5) {
441:     DM          dmBC;
442:     Vec         gv;
443:     const char *name;

445:     DMGetOutputDM(dm, &dmBC);
446:     DMGetGlobalVector(dmBC, &gv);
447:     PetscObjectGetName((PetscObject) v, &name);
448:     PetscObjectSetName((PetscObject) gv, name);
449:     VecLoad_Default(gv, viewer);
450:     DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);
451:     DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);
452:     DMRestoreGlobalVector(dmBC, &gv);
453:   } else {
454:     VecLoad_Default(v, viewer);
455:   }
456:   return(0);
457: }

459: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
460: {
461:   DM             dm;
462:   PetscBool      ishdf5;

466:   VecGetDM(v, &dm);
467:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
468:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
469:   if (ishdf5) {
470: #if defined(PETSC_HAVE_HDF5)
471:     VecLoad_Plex_HDF5_Internal(v, viewer);
472: #else
473:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
474: #endif
475:   } else {
476:     VecLoad_Default(v, viewer);
477:   }
478:   return(0);
479: }

481: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
482: {
483:   DM                dm;
484:   PetscViewerFormat format;
485:   PetscBool         ishdf5;
486:   PetscErrorCode    ierr;

489:   VecGetDM(originalv, &dm);
490:   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
491:   PetscViewerGetFormat(viewer, &format);
492:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
493:   if (format == PETSC_VIEWER_NATIVE) {
494:     if (dm->sfNatural) {
495:       if (ishdf5) {
496: #if defined(PETSC_HAVE_HDF5)
497:         Vec         v;
498:         const char *vecname;

500:         DMGetGlobalVector(dm, &v);
501:         PetscObjectGetName((PetscObject) originalv, &vecname);
502:         PetscObjectSetName((PetscObject) v, vecname);
503:         VecLoad_Plex_HDF5_Native_Internal(v, viewer);
504:         DMPlexNaturalToGlobalBegin(dm, v, originalv);
505:         DMPlexNaturalToGlobalEnd(dm, v, originalv);
506:         DMRestoreGlobalVector(dm, &v);
507: #else
508:         SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
509: #endif
510:       } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
511:     }
512:   }
513:   return(0);
514: }

516: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
517: {
518:   PetscSection       coordSection;
519:   Vec                coordinates;
520:   DMLabel            depthLabel;
521:   const char        *name[4];
522:   const PetscScalar *a;
523:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
524:   PetscErrorCode     ierr;

527:   DMGetDimension(dm, &dim);
528:   DMGetCoordinatesLocal(dm, &coordinates);
529:   DMGetCoordinateSection(dm, &coordSection);
530:   DMPlexGetDepthLabel(dm, &depthLabel);
531:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
532:   PetscSectionGetChart(coordSection, &pStart, &pEnd);
533:   VecGetArrayRead(coordinates, &a);
534:   name[0]     = "vertex";
535:   name[1]     = "edge";
536:   name[dim-1] = "face";
537:   name[dim]   = "cell";
538:   for (c = cStart; c < cEnd; ++c) {
539:     PetscInt *closure = NULL;
540:     PetscInt  closureSize, cl;

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

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

571: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
572: {
573:   DM_Plex          *mesh = (DM_Plex*) dm->data;
574:   DM                cdm;
575:   DMLabel           markers;
576:   PetscSection      coordSection;
577:   Vec               coordinates;
578:   PetscViewerFormat format;
579:   PetscErrorCode    ierr;

582:   DMGetCoordinateDM(dm, &cdm);
583:   DMGetDefaultSection(cdm, &coordSection);
584:   DMGetCoordinatesLocal(dm, &coordinates);
585:   PetscViewerGetFormat(viewer, &format);
586:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
587:     const char *name;
588:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
589:     PetscInt    pStart, pEnd, p;
590:     PetscMPIInt rank, size;

592:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
593:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
594:     PetscObjectGetName((PetscObject) dm, &name);
595:     DMPlexGetChart(dm, &pStart, &pEnd);
596:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
597:     DMGetDimension(dm, &dim);
598:     DMPlexGetVTKCellHeight(dm, &cellHeight);
599:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");}
600:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");}
601:     if (cellHeight) {PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);}
602:     PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
603:     PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
604:     PetscViewerASCIIPushSynchronized(viewer);
605:     PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);
606:     for (p = pStart; p < pEnd; ++p) {
607:       PetscInt dof, off, s;

609:       PetscSectionGetDof(mesh->supportSection, p, &dof);
610:       PetscSectionGetOffset(mesh->supportSection, p, &off);
611:       for (s = off; s < off+dof; ++s) {
612:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);
613:       }
614:     }
615:     PetscViewerFlush(viewer);
616:     PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
617:     for (p = pStart; p < pEnd; ++p) {
618:       PetscInt dof, off, c;

620:       PetscSectionGetDof(mesh->coneSection, p, &dof);
621:       PetscSectionGetOffset(mesh->coneSection, p, &off);
622:       for (c = off; c < off+dof; ++c) {
623:         PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
624:       }
625:     }
626:     PetscViewerFlush(viewer);
627:     PetscViewerASCIIPopSynchronized(viewer);
628:     PetscSectionGetChart(coordSection, &pStart, NULL);
629:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
630:     DMGetLabel(dm, "marker", &markers);
631:     DMLabelView(markers,viewer);
632:     if (size > 1) {
633:       PetscSF sf;

635:       DMGetPointSF(dm, &sf);
636:       PetscSFView(sf, viewer);
637:     }
638:     PetscViewerFlush(viewer);
639:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
640:     const char  *name, *color;
641:     const char  *defcolors[3]  = {"gray", "orange", "green"};
642:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
643:     PetscReal    scale         = 2.0;
644:     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
645:     double       tcoords[3];
646:     PetscScalar *coords;
647:     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
648:     PetscMPIInt  rank, size;
649:     char         **names, **colors, **lcolors;

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

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

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

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

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

793:           if ((point < vStart) || (point >= vEnd)) continue;
794:           if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
795:           PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);
796:           if (firstPoint < 0) firstPoint = point;
797:         }
798:         /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
799:         PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);
800:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
801:       }
802:     }
803:     PetscViewerFlush(viewer);
804:     PetscViewerASCIIPopSynchronized(viewer);
805:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");
806:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
807:     for (l = 0; l < numLabels;  ++l) {PetscFree(names[l]);}
808:     for (c = 0; c < numColors;  ++c) {PetscFree(colors[c]);}
809:     for (c = 0; c < numLColors; ++c) {PetscFree(lcolors[c]);}
810:     PetscFree3(names, colors, lcolors);
811:   } else {
812:     MPI_Comm    comm;
813:     PetscInt   *sizes, *hybsizes;
814:     PetscInt    locDepth, depth, cellHeight, dim, d, pMax[4];
815:     PetscInt    pStart, pEnd, p;
816:     PetscInt    numLabels, l;
817:     const char *name;
818:     PetscMPIInt size;

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

874:       DMGetLabelName(dm, l, &name);
875:       DMGetLabel(dm, name, &label);
876:       DMLabelGetNumValues(label, &numValues);
877:       PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);
878:       DMLabelGetValueIS(label, &valueIS);
879:       ISGetIndices(valueIS, &values);
880:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
881:       for (v = 0; v < numValues; ++v) {
882:         PetscInt size;

884:         DMLabelGetStratumSize(label, values[v], &size);
885:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
886:         PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);
887:       }
888:       PetscViewerASCIIPrintf(viewer, ")\n");
889:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
890:       ISRestoreIndices(valueIS, &values);
891:       ISDestroy(&valueIS);
892:     }
893:     DMGetCoarseDM(dm, &cdm);
894:     if (cdm) {
895:       PetscViewerASCIIPushTab(viewer);
896:       DMPlexView_Ascii(cdm, viewer);
897:       PetscViewerASCIIPopTab(viewer);
898:     }
899:   }
900:   return(0);
901: }

903: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
904: {
905:   PetscDraw          draw;
906:   DM                 cdm;
907:   PetscSection       coordSection;
908:   Vec                coordinates;
909:   const PetscScalar *coords;
910:   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
911:   PetscBool          isnull;
912:   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N;
913:   PetscErrorCode     ierr;

916:   DMGetCoordinateDim(dm, &dim);
917:   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
918:   DMGetCoordinateDM(dm, &cdm);
919:   DMGetDefaultSection(cdm, &coordSection);
920:   DMGetCoordinatesLocal(dm, &coordinates);
921:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
922:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

924:   PetscViewerDrawGetDraw(viewer, 0, &draw);
925:   PetscDrawIsNull(draw, &isnull);
926:   if (isnull) return(0);
927:   PetscDrawSetTitle(draw, "Mesh");

929:   VecGetLocalSize(coordinates, &N);
930:   VecGetArrayRead(coordinates, &coords);
931:   for (c = 0; c < N; c += dim) {
932:     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
933:     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
934:   }
935:   VecRestoreArrayRead(coordinates, &coords);
936:   MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));
937:   MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));
938:   PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);
939:   PetscDrawClear(draw);

941:   for (c = cStart; c < cEnd; ++c) {
942:     PetscScalar *coords = NULL;
943:     PetscInt     numCoords,coneSize;

945:     DMPlexGetConeSize(dm, c, &coneSize);
946:     DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
947:     switch (coneSize) {
948:     case 3:
949:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
950:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
951:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
952:       break;
953:     case 4:
954:       PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);
955:       PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);
956:       PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);
957:       PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);
958:       break;
959:     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D facets", coneSize);
960:     }
961:     DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);
962:   }
963:   PetscDrawFlush(draw);
964:   PetscDrawPause(draw);
965:   PetscDrawSave(draw);
966:   return(0);
967: }

969: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
970: {
971:   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis;
972:   PetscErrorCode    ierr;

977:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
978:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);
979:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);
980:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);
981:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);
982:   if (iascii) {
983:     PetscViewerFormat format;
984:     PetscViewerGetFormat(viewer, &format);
985:     if (format == PETSC_VIEWER_ASCII_GLVIS) {
986:       DMPlexView_GLVis(dm, viewer);
987:     } else {
988:       DMPlexView_Ascii(dm, viewer);
989:     }
990:   } else if (ishdf5) {
991: #if defined(PETSC_HAVE_HDF5)
992:     PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);
993:     DMPlexView_HDF5_Internal(dm, viewer);
994:     PetscViewerPopFormat(viewer);
995: #else
996:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
997: #endif
998:   } else if (isvtk) {
999:     DMPlexVTKWriteAll((PetscObject) dm,viewer);
1000:   } else if (isdraw) {
1001:     DMPlexView_Draw(dm, viewer);
1002:   } else if (isglvis) {
1003:     DMPlexView_GLVis(dm, viewer);
1004:   }
1005:   /* Optionally view the partition */
1006:   PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);
1007:   if (flg) {
1008:     Vec ranks;
1009:     DMPlexCreateRankField(dm, &ranks);
1010:     VecView(ranks, viewer);
1011:     VecDestroy(&ranks);
1012:   }
1013:   return(0);
1014: }

1016: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1017: {
1018:   PetscBool      isbinary, ishdf5;

1024:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
1025:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);
1026:   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
1027:   else if (ishdf5) {
1028: #if defined(PETSC_HAVE_HDF5)
1029:     DMPlexLoad_HDF5_Internal(dm, viewer);
1030: #else
1031:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1032: #endif
1033:   }
1034:   return(0);
1035: }

1037: PetscErrorCode DMDestroy_Plex(DM dm)
1038: {
1039:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1043:   PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);
1044:   PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);
1045:   if (--mesh->refct > 0) return(0);
1046:   PetscSectionDestroy(&mesh->coneSection);
1047:   PetscFree(mesh->cones);
1048:   PetscFree(mesh->coneOrientations);
1049:   PetscSectionDestroy(&mesh->supportSection);
1050:   PetscSectionDestroy(&mesh->subdomainSection);
1051:   PetscFree(mesh->supports);
1052:   PetscFree(mesh->facesTmp);
1053:   PetscFree(mesh->tetgenOpts);
1054:   PetscFree(mesh->triangleOpts);
1055:   PetscPartitionerDestroy(&mesh->partitioner);
1056:   DMLabelDestroy(&mesh->subpointMap);
1057:   ISDestroy(&mesh->globalVertexNumbers);
1058:   ISDestroy(&mesh->globalCellNumbers);
1059:   PetscSectionDestroy(&mesh->anchorSection);
1060:   ISDestroy(&mesh->anchorIS);
1061:   PetscSectionDestroy(&mesh->parentSection);
1062:   PetscFree(mesh->parents);
1063:   PetscFree(mesh->childIDs);
1064:   PetscSectionDestroy(&mesh->childSection);
1065:   PetscFree(mesh->children);
1066:   DMDestroy(&mesh->referenceTree);
1067:   PetscGridHashDestroy(&mesh->lbox);
1068:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1069:   PetscFree(mesh);
1070:   return(0);
1071: }

1073: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1074: {
1075:   PetscSection           sectionGlobal;
1076:   PetscInt               bs = -1, mbs;
1077:   PetscInt               localSize;
1078:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1079:   PetscErrorCode         ierr;
1080:   MatType                mtype;
1081:   ISLocalToGlobalMapping ltog;

1084:   MatInitializePackage();
1085:   mtype = dm->mattype;
1086:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
1087:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
1088:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
1089:   MatCreate(PetscObjectComm((PetscObject)dm), J);
1090:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
1091:   MatSetType(*J, mtype);
1092:   MatSetFromOptions(*J);
1093:   MatGetBlockSize(*J, &mbs);
1094:   if (mbs > 1) bs = mbs;
1095:   PetscStrcmp(mtype, MATSHELL, &isShell);
1096:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
1097:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
1098:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
1099:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
1100:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
1101:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
1102:   PetscStrcmp(mtype, MATIS, &isMatIS);
1103:   if (!isShell) {
1104:     PetscSection subSection;
1105:     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
1106:     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
1107:     PetscInt     pStart, pEnd, p, dof, cdof;

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

1114:       DMGetDefaultSection(dm, &section);
1115:       PetscSectionGetStorageSize(section, &size);
1116:       PetscMalloc1(size,&ltogidx);
1117:       DMPlexGetSubdomainSection(dm, &subSection);
1118:     } else {
1119:       DMGetLocalToGlobalMapping(dm,&ltog);
1120:     }
1121:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1122:     for (p = pStart, lsize = 0; p < pEnd; ++p) {
1123:       PetscInt bdof;

1125:       PetscSectionGetDof(sectionGlobal, p, &dof);
1126:       PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
1127:       dof  = dof < 0 ? -(dof+1) : dof;
1128:       bdof = cdof && (dof-cdof) ? 1 : dof;
1129:       if (dof) {
1130:         if (bs < 0)          {bs = bdof;}
1131:         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
1132:       }
1133:       if (isMatIS) {
1134:         PetscInt loff,c,off;
1135:         PetscSectionGetOffset(subSection, p, &loff);
1136:         PetscSectionGetOffset(sectionGlobal, p, &off);
1137:         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
1138:       }
1139:     }
1140:     /* Must have same blocksize on all procs (some might have no points) */
1141:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1142:     PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1143:     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1144:     else                            {bs = bsMinMax[0];}
1145:     bs = bs < 0 ? 1 : bs;
1146:     if (isMatIS) {
1147:       PetscInt l;
1148:       /* Must reduce indices by blocksize */
1149:       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] /= bs;
1150:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);
1151:     }
1152:     MatSetLocalToGlobalMapping(*J,ltog,ltog);
1153:     if (isMatIS) {
1154:       ISLocalToGlobalMappingDestroy(&ltog);
1155:     }
1156:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
1157:     DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);
1158:     PetscFree4(dnz, onz, dnzu, onzu);
1159:   }
1160:   MatSetDM(*J, dm);
1161:   return(0);
1162: }

1164: /*@
1165:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

1167:   Not collective

1169:   Input Parameter:
1170: . mesh - The DMPlex

1172:   Output Parameters:
1173: . subsection - The subdomain section

1175:   Level: developer

1177: .seealso:
1178: @*/
1179: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
1180: {
1181:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1186:   if (!mesh->subdomainSection) {
1187:     PetscSection section;
1188:     PetscSF      sf;

1190:     PetscSFCreate(PETSC_COMM_SELF,&sf);
1191:     DMGetDefaultSection(dm,&section);
1192:     PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);
1193:     PetscSFDestroy(&sf);
1194:   }
1195:   *subsection = mesh->subdomainSection;
1196:   return(0);
1197: }

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

1202:   Not collective

1204:   Input Parameter:
1205: . mesh - The DMPlex

1207:   Output Parameters:
1208: + pStart - The first mesh point
1209: - pEnd   - The upper bound for mesh points

1211:   Level: beginner

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

1222:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
1223:   return(0);
1224: }

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

1229:   Not collective

1231:   Input Parameters:
1232: + mesh - The DMPlex
1233: . pStart - The first mesh point
1234: - pEnd   - The upper bound for mesh points

1236:   Output Parameters:

1238:   Level: beginner

1240: .seealso: DMPlexCreate(), DMPlexGetChart()
1241: @*/
1242: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1243: {
1244:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1249:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
1250:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
1251:   return(0);
1252: }

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

1257:   Not collective

1259:   Input Parameters:
1260: + mesh - The DMPlex
1261: - p - The point, which must lie in the chart set with DMPlexSetChart()

1263:   Output Parameter:
1264: . size - The cone size for point p

1266:   Level: beginner

1268: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1269: @*/
1270: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1271: {
1272:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1278:   PetscSectionGetDof(mesh->coneSection, p, size);
1279:   return(0);
1280: }

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

1285:   Not collective

1287:   Input Parameters:
1288: + mesh - The DMPlex
1289: . p - The point, which must lie in the chart set with DMPlexSetChart()
1290: - size - The cone size for point p

1292:   Output Parameter:

1294:   Note:
1295:   This should be called after DMPlexSetChart().

1297:   Level: beginner

1299: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1300: @*/
1301: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1302: {
1303:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1310:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1311:   return(0);
1312: }

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

1317:   Not collective

1319:   Input Parameters:
1320: + mesh - The DMPlex
1321: . p - The point, which must lie in the chart set with DMPlexSetChart()
1322: - size - The additional cone size for point p

1324:   Output Parameter:

1326:   Note:
1327:   This should be called after DMPlexSetChart().

1329:   Level: beginner

1331: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
1332: @*/
1333: PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
1334: {
1335:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1336:   PetscInt       csize;

1341:   PetscSectionAddDof(mesh->coneSection, p, size);
1342:   PetscSectionGetDof(mesh->coneSection, p, &csize);

1344:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
1345:   return(0);
1346: }

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

1351:   Not collective

1353:   Input Parameters:
1354: + mesh - The DMPlex
1355: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1360:   Level: beginner

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

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

1368: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1369: @*/
1370: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1371: {
1372:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1373:   PetscInt       off;

1379:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1380:   *cone = &mesh->cones[off];
1381:   return(0);
1382: }

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

1387:   Not collective

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

1394:   Output Parameter:

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

1399:   Level: beginner

1401: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1402: @*/
1403: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1404: {
1405:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1406:   PetscInt       pStart, pEnd;
1407:   PetscInt       dof, off, c;

1412:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1413:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1415:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1416:   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);
1417:   for (c = 0; c < dof; ++c) {
1418:     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);
1419:     mesh->cones[off+c] = cone[c];
1420:   }
1421:   return(0);
1422: }

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

1427:   Not collective

1429:   Input Parameters:
1430: + mesh - The DMPlex
1431: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1439:   Level: beginner

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

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

1447: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1448: @*/
1449: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1450: {
1451:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1452:   PetscInt       off;

1457: #if defined(PETSC_USE_DEBUG)
1458:   {
1459:     PetscInt dof;
1460:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1462:   }
1463: #endif
1464:   PetscSectionGetOffset(mesh->coneSection, p, &off);

1466:   *coneOrientation = &mesh->coneOrientations[off];
1467:   return(0);
1468: }

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

1473:   Not collective

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

1483:   Output Parameter:

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

1488:   Level: beginner

1490: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1491: @*/
1492: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1493: {
1494:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1495:   PetscInt       pStart, pEnd;
1496:   PetscInt       dof, off, c;

1501:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1502:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1504:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1505:   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);
1506:   for (c = 0; c < dof; ++c) {
1507:     PetscInt cdof, o = coneOrientation[c];

1509:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
1510:     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);
1511:     mesh->coneOrientations[off+c] = o;
1512:   }
1513:   return(0);
1514: }

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

1519:   Not collective

1521:   Input Parameters:
1522: + mesh - The DMPlex
1523: . p - The point, which must lie in the chart set with DMPlexSetChart()
1524: . conePos - The local index in the cone where the point should be put
1525: - conePoint - The mesh point to insert

1527:   Level: beginner

1529: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1530: @*/
1531: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1532: {
1533:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1534:   PetscInt       pStart, pEnd;
1535:   PetscInt       dof, off;

1540:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1541:   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);
1542:   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);
1543:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1544:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1545:   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);
1546:   mesh->cones[off+conePos] = conePoint;
1547:   return(0);
1548: }

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

1553:   Not collective

1555:   Input Parameters:
1556: + mesh - The DMPlex
1557: . p - The point, which must lie in the chart set with DMPlexSetChart()
1558: . conePos - The local index in the cone where the point should be put
1559: - coneOrientation - The point orientation to insert

1561:   Level: beginner

1563: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1564: @*/
1565: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1566: {
1567:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1568:   PetscInt       pStart, pEnd;
1569:   PetscInt       dof, off;

1574:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1575:   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);
1576:   PetscSectionGetDof(mesh->coneSection, p, &dof);
1577:   PetscSectionGetOffset(mesh->coneSection, p, &off);
1578:   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);
1579:   mesh->coneOrientations[off+conePos] = coneOrientation;
1580:   return(0);
1581: }

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

1586:   Not collective

1588:   Input Parameters:
1589: + mesh - The DMPlex
1590: - p - The point, which must lie in the chart set with DMPlexSetChart()

1592:   Output Parameter:
1593: . size - The support size for point p

1595:   Level: beginner

1597: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1598: @*/
1599: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1600: {
1601:   DM_Plex       *mesh = (DM_Plex*) dm->data;

1607:   PetscSectionGetDof(mesh->supportSection, p, size);
1608:   return(0);
1609: }

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

1614:   Not collective

1616:   Input Parameters:
1617: + mesh - The DMPlex
1618: . p - The point, which must lie in the chart set with DMPlexSetChart()
1619: - size - The support size for point p

1621:   Output Parameter:

1623:   Note:
1624:   This should be called after DMPlexSetChart().

1626:   Level: beginner

1628: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1629: @*/
1630: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1631: {
1632:   DM_Plex       *mesh = (DM_Plex*) dm->data;

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

1639:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1640:   return(0);
1641: }

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

1646:   Not collective

1648:   Input Parameters:
1649: + mesh - The DMPlex
1650: - p - The point, which must lie in the chart set with DMPlexSetChart()

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

1655:   Level: beginner

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

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

1663: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1664: @*/
1665: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1666: {
1667:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1668:   PetscInt       off;

1674:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1675:   *support = &mesh->supports[off];
1676:   return(0);
1677: }

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

1682:   Not collective

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

1689:   Output Parameter:

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

1694:   Level: beginner

1696: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1697: @*/
1698: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1699: {
1700:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1701:   PetscInt       pStart, pEnd;
1702:   PetscInt       dof, off, c;

1707:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1708:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1710:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1711:   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);
1712:   for (c = 0; c < dof; ++c) {
1713:     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);
1714:     mesh->supports[off+c] = support[c];
1715:   }
1716:   return(0);
1717: }

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

1722:   Not collective

1724:   Input Parameters:
1725: + mesh - The DMPlex
1726: . p - The point, which must lie in the chart set with DMPlexSetChart()
1727: . supportPos - The local index in the cone where the point should be put
1728: - supportPoint - The mesh point to insert

1730:   Level: beginner

1732: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1733: @*/
1734: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1735: {
1736:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1737:   PetscInt       pStart, pEnd;
1738:   PetscInt       dof, off;

1743:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1744:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1745:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1746:   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);
1747:   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);
1748:   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);
1749:   mesh->supports[off+supportPos] = supportPoint;
1750:   return(0);
1751: }

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

1756:   Not collective

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

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

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

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

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

1777:   Level: beginner

1779: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1780: @*/
1781: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1782: {
1783:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1784:   PetscInt       *closure, *fifo;
1785:   const PetscInt *tmp = NULL, *tmpO = NULL;
1786:   PetscInt        tmpSize, t;
1787:   PetscInt        depth       = 0, maxSize;
1788:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1789:   PetscErrorCode  ierr;

1793:   DMPlexGetDepth(dm, &depth);
1794:   /* This is only 1-level */
1795:   if (useCone) {
1796:     DMPlexGetConeSize(dm, p, &tmpSize);
1797:     DMPlexGetCone(dm, p, &tmp);
1798:     DMPlexGetConeOrientation(dm, p, &tmpO);
1799:   } else {
1800:     DMPlexGetSupportSize(dm, p, &tmpSize);
1801:     DMPlexGetSupport(dm, p, &tmp);
1802:   }
1803:   if (depth == 1) {
1804:     if (*points) {
1805:       closure = *points;
1806:     } else {
1807:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1808:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1809:     }
1810:     closure[0] = p; closure[1] = 0;
1811:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1812:       closure[closureSize]   = tmp[t];
1813:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1814:     }
1815:     if (numPoints) *numPoints = closureSize/2;
1816:     if (points)    *points    = closure;
1817:     return(0);
1818:   }
1819:   {
1820:     PetscInt c, coneSeries, s,supportSeries;

1822:     c = mesh->maxConeSize;
1823:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1824:     s = mesh->maxSupportSize;
1825:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1826:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1827:   }
1828:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
1829:   if (*points) {
1830:     closure = *points;
1831:   } else {
1832:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1833:   }
1834:   closure[0] = p; closure[1] = 0;
1835:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1836:     const PetscInt cp = tmp[t];
1837:     const PetscInt co = tmpO ? tmpO[t] : 0;

1839:     closure[closureSize]   = cp;
1840:     closure[closureSize+1] = co;
1841:     fifo[fifoSize]         = cp;
1842:     fifo[fifoSize+1]       = co;
1843:   }
1844:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1845:   while (fifoSize - fifoStart) {
1846:     const PetscInt q   = fifo[fifoStart];
1847:     const PetscInt o   = fifo[fifoStart+1];
1848:     const PetscInt rev = o >= 0 ? 0 : 1;
1849:     const PetscInt off = rev ? -(o+1) : o;

1851:     if (useCone) {
1852:       DMPlexGetConeSize(dm, q, &tmpSize);
1853:       DMPlexGetCone(dm, q, &tmp);
1854:       DMPlexGetConeOrientation(dm, q, &tmpO);
1855:     } else {
1856:       DMPlexGetSupportSize(dm, q, &tmpSize);
1857:       DMPlexGetSupport(dm, q, &tmp);
1858:       tmpO = NULL;
1859:     }
1860:     for (t = 0; t < tmpSize; ++t) {
1861:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1862:       const PetscInt cp = tmp[i];
1863:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1864:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1865:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1866:       PetscInt       co = tmpO ? tmpO[i] : 0;
1867:       PetscInt       c;

1869:       if (rev) {
1870:         PetscInt childSize, coff;
1871:         DMPlexGetConeSize(dm, cp, &childSize);
1872:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1873:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1874:       }
1875:       /* Check for duplicate */
1876:       for (c = 0; c < closureSize; c += 2) {
1877:         if (closure[c] == cp) break;
1878:       }
1879:       if (c == closureSize) {
1880:         closure[closureSize]   = cp;
1881:         closure[closureSize+1] = co;
1882:         fifo[fifoSize]         = cp;
1883:         fifo[fifoSize+1]       = co;
1884:         closureSize           += 2;
1885:         fifoSize              += 2;
1886:       }
1887:     }
1888:     fifoStart += 2;
1889:   }
1890:   if (numPoints) *numPoints = closureSize/2;
1891:   if (points)    *points    = closure;
1892:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
1893:   return(0);
1894: }

1896: /*@C
1897:   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

1899:   Not collective

1901:   Input Parameters:
1902: + mesh - The DMPlex
1903: . p - The point, which must lie in the chart set with DMPlexSetChart()
1904: . orientation - The orientation of the point
1905: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1906: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

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

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

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

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

1921:   Level: beginner

1923: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1924: @*/
1925: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1926: {
1927:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1928:   PetscInt       *closure, *fifo;
1929:   const PetscInt *tmp = NULL, *tmpO = NULL;
1930:   PetscInt        tmpSize, t;
1931:   PetscInt        depth       = 0, maxSize;
1932:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1933:   PetscErrorCode  ierr;

1937:   DMPlexGetDepth(dm, &depth);
1938:   /* This is only 1-level */
1939:   if (useCone) {
1940:     DMPlexGetConeSize(dm, p, &tmpSize);
1941:     DMPlexGetCone(dm, p, &tmp);
1942:     DMPlexGetConeOrientation(dm, p, &tmpO);
1943:   } else {
1944:     DMPlexGetSupportSize(dm, p, &tmpSize);
1945:     DMPlexGetSupport(dm, p, &tmp);
1946:   }
1947:   if (depth == 1) {
1948:     if (*points) {
1949:       closure = *points;
1950:     } else {
1951:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1952:       DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1953:     }
1954:     closure[0] = p; closure[1] = ornt;
1955:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1956:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1957:       closure[closureSize]   = tmp[i];
1958:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1959:     }
1960:     if (numPoints) *numPoints = closureSize/2;
1961:     if (points)    *points    = closure;
1962:     return(0);
1963:   }
1964:   {
1965:     PetscInt c, coneSeries, s,supportSeries;

1967:     c = mesh->maxConeSize;
1968:     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1969:     s = mesh->maxSupportSize;
1970:     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1971:     maxSize = 2*PetscMax(coneSeries,supportSeries);
1972:   }
1973:   DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);
1974:   if (*points) {
1975:     closure = *points;
1976:   } else {
1977:     DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);
1978:   }
1979:   closure[0] = p; closure[1] = ornt;
1980:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1981:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1982:     const PetscInt cp = tmp[i];
1983:     PetscInt       co = tmpO ? tmpO[i] : 0;

1985:     if (ornt < 0) {
1986:       PetscInt childSize, coff;
1987:       DMPlexGetConeSize(dm, cp, &childSize);
1988:       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
1989:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1990:     }
1991:     closure[closureSize]   = cp;
1992:     closure[closureSize+1] = co;
1993:     fifo[fifoSize]         = cp;
1994:     fifo[fifoSize+1]       = co;
1995:   }
1996:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1997:   while (fifoSize - fifoStart) {
1998:     const PetscInt q   = fifo[fifoStart];
1999:     const PetscInt o   = fifo[fifoStart+1];
2000:     const PetscInt rev = o >= 0 ? 0 : 1;
2001:     const PetscInt off = rev ? -(o+1) : o;

2003:     if (useCone) {
2004:       DMPlexGetConeSize(dm, q, &tmpSize);
2005:       DMPlexGetCone(dm, q, &tmp);
2006:       DMPlexGetConeOrientation(dm, q, &tmpO);
2007:     } else {
2008:       DMPlexGetSupportSize(dm, q, &tmpSize);
2009:       DMPlexGetSupport(dm, q, &tmp);
2010:       tmpO = NULL;
2011:     }
2012:     for (t = 0; t < tmpSize; ++t) {
2013:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2014:       const PetscInt cp = tmp[i];
2015:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2016:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2017:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2018:       PetscInt       co = tmpO ? tmpO[i] : 0;
2019:       PetscInt       c;

2021:       if (rev) {
2022:         PetscInt childSize, coff;
2023:         DMPlexGetConeSize(dm, cp, &childSize);
2024:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2025:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2026:       }
2027:       /* Check for duplicate */
2028:       for (c = 0; c < closureSize; c += 2) {
2029:         if (closure[c] == cp) break;
2030:       }
2031:       if (c == closureSize) {
2032:         closure[closureSize]   = cp;
2033:         closure[closureSize+1] = co;
2034:         fifo[fifoSize]         = cp;
2035:         fifo[fifoSize+1]       = co;
2036:         closureSize           += 2;
2037:         fifoSize              += 2;
2038:       }
2039:     }
2040:     fifoStart += 2;
2041:   }
2042:   if (numPoints) *numPoints = closureSize/2;
2043:   if (points)    *points    = closure;
2044:   DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);
2045:   return(0);
2046: }

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

2051:   Not collective

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

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

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

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

2069:   Level: beginner

2071: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2072: @*/
2073: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2074: {

2081:   DMRestoreWorkArray(dm, 0, MPIU_INT, points);
2082:   if (numPoints) *numPoints = 0;
2083:   return(0);
2084: }

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

2089:   Not collective

2091:   Input Parameter:
2092: . mesh - The DMPlex

2094:   Output Parameters:
2095: + maxConeSize - The maximum number of in-edges
2096: - maxSupportSize - The maximum number of out-edges

2098:   Level: beginner

2100: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2101: @*/
2102: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2103: {
2104:   DM_Plex *mesh = (DM_Plex*) dm->data;

2108:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2109:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2110:   return(0);
2111: }

2113: PetscErrorCode DMSetUp_Plex(DM dm)
2114: {
2115:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2116:   PetscInt       size;

2121:   PetscSectionSetUp(mesh->coneSection);
2122:   PetscSectionGetStorageSize(mesh->coneSection, &size);
2123:   PetscMalloc1(size, &mesh->cones);
2124:   PetscCalloc1(size, &mesh->coneOrientations);
2125:   if (mesh->maxSupportSize) {
2126:     PetscSectionSetUp(mesh->supportSection);
2127:     PetscSectionGetStorageSize(mesh->supportSection, &size);
2128:     PetscMalloc1(size, &mesh->supports);
2129:   }
2130:   return(0);
2131: }

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

2138:   if (subdm) {DMClone(dm, subdm);}
2139:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
2140:   return(0);
2141: }

2143: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2144: {

2148:   if (superdm) {DMClone(dms[0], superdm);}
2149:   DMCreateSuperDM_Section_Private(dms, len, is, superdm);
2150:   return(0);
2151: }

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

2156:   Not collective

2158:   Input Parameter:
2159: . mesh - The DMPlex

2161:   Output Parameter:

2163:   Note:
2164:   This should be called after all calls to DMPlexSetCone()

2166:   Level: beginner

2168: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2169: @*/
2170: PetscErrorCode DMPlexSymmetrize(DM dm)
2171: {
2172:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2173:   PetscInt      *offsets;
2174:   PetscInt       supportSize;
2175:   PetscInt       pStart, pEnd, p;

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

2186:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2187:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2188:     for (c = off; c < off+dof; ++c) {
2189:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
2190:     }
2191:   }
2192:   for (p = pStart; p < pEnd; ++p) {
2193:     PetscInt dof;

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

2197:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2198:   }
2199:   PetscSectionSetUp(mesh->supportSection);
2200:   /* Calculate supports */
2201:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
2202:   PetscMalloc1(supportSize, &mesh->supports);
2203:   PetscCalloc1(pEnd - pStart, &offsets);
2204:   for (p = pStart; p < pEnd; ++p) {
2205:     PetscInt dof, off, c;

2207:     PetscSectionGetDof(mesh->coneSection, p, &dof);
2208:     PetscSectionGetOffset(mesh->coneSection, p, &off);
2209:     for (c = off; c < off+dof; ++c) {
2210:       const PetscInt q = mesh->cones[c];
2211:       PetscInt       offS;

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

2215:       mesh->supports[offS+offsets[q]] = p;
2216:       ++offsets[q];
2217:     }
2218:   }
2219:   PetscFree(offsets);
2220:   return(0);
2221: }

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

2229:   Collective on dm

2231:   Input Parameter:
2232: . mesh - The DMPlex

2234:   Output Parameter:

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

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

2244:   Level: beginner

2246: .seealso: DMPlexCreate(), DMPlexSymmetrize()
2247: @*/
2248: PetscErrorCode DMPlexStratify(DM dm)
2249: {
2250:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2251:   DMLabel        label;
2252:   PetscInt       pStart, pEnd, p;
2253:   PetscInt       numRoots = 0, numLeaves = 0;

2258:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
2259:   /* Calculate depth */
2260:   DMPlexGetChart(dm, &pStart, &pEnd);
2261:   DMCreateLabel(dm, "depth");
2262:   DMPlexGetDepthLabel(dm, &label);
2263:   /* Initialize roots and count leaves */
2264:   for (p = pStart; p < pEnd; ++p) {
2265:     PetscInt coneSize, supportSize;

2267:     DMPlexGetConeSize(dm, p, &coneSize);
2268:     DMPlexGetSupportSize(dm, p, &supportSize);
2269:     if (!coneSize && supportSize) {
2270:       ++numRoots;
2271:       DMLabelSetValue(label, p, 0);
2272:     } else if (!supportSize && coneSize) {
2273:       ++numLeaves;
2274:     } else if (!supportSize && !coneSize) {
2275:       /* Isolated points */
2276:       DMLabelSetValue(label, p, 0);
2277:     }
2278:   }
2279:   if (numRoots + numLeaves == (pEnd - pStart)) {
2280:     for (p = pStart; p < pEnd; ++p) {
2281:       PetscInt coneSize, supportSize;

2283:       DMPlexGetConeSize(dm, p, &coneSize);
2284:       DMPlexGetSupportSize(dm, p, &supportSize);
2285:       if (!supportSize && coneSize) {
2286:         DMLabelSetValue(label, p, 1);
2287:       }
2288:     }
2289:   } else {
2290:     IS       pointIS;
2291:     PetscInt numPoints = 0, level = 0;

2293:     DMLabelGetStratumIS(label, level, &pointIS);
2294:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2295:     while (numPoints) {
2296:       const PetscInt *points;
2297:       const PetscInt  newLevel = level+1;

2299:       ISGetIndices(pointIS, &points);
2300:       for (p = 0; p < numPoints; ++p) {
2301:         const PetscInt  point = points[p];
2302:         const PetscInt *support;
2303:         PetscInt        supportSize, s;

2305:         DMPlexGetSupportSize(dm, point, &supportSize);
2306:         DMPlexGetSupport(dm, point, &support);
2307:         for (s = 0; s < supportSize; ++s) {
2308:           DMLabelSetValue(label, support[s], newLevel);
2309:         }
2310:       }
2311:       ISRestoreIndices(pointIS, &points);
2312:       ++level;
2313:       ISDestroy(&pointIS);
2314:       DMLabelGetStratumIS(label, level, &pointIS);
2315:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
2316:       else         {numPoints = 0;}
2317:     }
2318:     ISDestroy(&pointIS);
2319:   }
2320:   { /* just in case there is an empty process */
2321:     PetscInt numValues, maxValues = 0, v;

2323:     DMLabelGetNumValues(label,&numValues);
2324:     for (v = 0; v < numValues; v++) {
2325:       IS pointIS;

2327:       DMLabelGetStratumIS(label, v, &pointIS);
2328:       if (pointIS) {
2329:         PetscInt  min, max, numPoints;
2330:         PetscInt  start;
2331:         PetscBool contig;

2333:         ISGetLocalSize(pointIS, &numPoints);
2334:         ISGetMinMax(pointIS, &min, &max);
2335:         ISContiguousLocal(pointIS,min,max+1,&start,&contig);
2336:         if (start == 0 && contig) {
2337:           ISDestroy(&pointIS);
2338:           ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);
2339:           DMLabelSetStratumIS(label, v, pointIS);
2340:         }
2341:       }
2342:       ISDestroy(&pointIS);
2343:     }
2344:     MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
2345:     for (v = numValues; v < maxValues; v++) {
2346:       DMLabelAddStratum(label,v);
2347:     }
2348:   }

2350:   DMLabelGetState(label, &mesh->depthState);
2351:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
2352:   return(0);
2353: }

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

2358:   Not Collective

2360:   Input Parameters:
2361: + dm - The DMPlex object
2362: . numPoints - The number of input points for the join
2363: - points - The input points

2365:   Output Parameters:
2366: + numCoveredPoints - The number of points in the join
2367: - coveredPoints - The points in the join

2369:   Level: intermediate

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

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

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

2379: .keywords: mesh
2380: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2381: @*/
2382: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2383: {
2384:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2385:   PetscInt      *join[2];
2386:   PetscInt       joinSize, i = 0;
2387:   PetscInt       dof, off, p, c, m;

2395:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);
2396:   DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);
2397:   /* Copy in support of first point */
2398:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
2399:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
2400:   for (joinSize = 0; joinSize < dof; ++joinSize) {
2401:     join[i][joinSize] = mesh->supports[off+joinSize];
2402:   }
2403:   /* Check each successive support */
2404:   for (p = 1; p < numPoints; ++p) {
2405:     PetscInt newJoinSize = 0;

2407:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
2408:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
2409:     for (c = 0; c < dof; ++c) {
2410:       const PetscInt point = mesh->supports[off+c];

2412:       for (m = 0; m < joinSize; ++m) {
2413:         if (point == join[i][m]) {
2414:           join[1-i][newJoinSize++] = point;
2415:           break;
2416:         }
2417:       }
2418:     }
2419:     joinSize = newJoinSize;
2420:     i        = 1-i;
2421:   }
2422:   *numCoveredPoints = joinSize;
2423:   *coveredPoints    = join[i];
2424:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2425:   return(0);
2426: }

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

2431:   Not Collective

2433:   Input Parameters:
2434: + dm - The DMPlex object
2435: . numPoints - The number of input points for the join
2436: - points - The input points

2438:   Output Parameters:
2439: + numCoveredPoints - The number of points in the join
2440: - coveredPoints - The points in the join

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

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

2448:   Level: intermediate

2450: .keywords: mesh
2451: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2452: @*/
2453: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2454: {

2462:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2463:   if (numCoveredPoints) *numCoveredPoints = 0;
2464:   return(0);
2465: }

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

2470:   Not Collective

2472:   Input Parameters:
2473: + dm - The DMPlex object
2474: . numPoints - The number of input points for the join
2475: - points - The input points

2477:   Output Parameters:
2478: + numCoveredPoints - The number of points in the join
2479: - coveredPoints - The points in the join

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

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

2487:   Level: intermediate

2489: .keywords: mesh
2490: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2491: @*/
2492: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2493: {
2494:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2495:   PetscInt      *offsets, **closures;
2496:   PetscInt      *join[2];
2497:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2498:   PetscInt       p, d, c, m, ms;


2507:   DMPlexGetDepth(dm, &depth);
2508:   PetscCalloc1(numPoints, &closures);
2509:   DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2510:   ms      = mesh->maxSupportSize;
2511:   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2512:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);
2513:   DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);

2515:   for (p = 0; p < numPoints; ++p) {
2516:     PetscInt closureSize;

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

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

2524:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
2525:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2526:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2527:           offsets[p*(depth+2)+d+1] = i;
2528:           break;
2529:         }
2530:       }
2531:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2532:     }
2533:     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);
2534:   }
2535:   for (d = 0; d < depth+1; ++d) {
2536:     PetscInt dof;

2538:     /* Copy in support of first point */
2539:     dof = offsets[d+1] - offsets[d];
2540:     for (joinSize = 0; joinSize < dof; ++joinSize) {
2541:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2542:     }
2543:     /* Check each successive cone */
2544:     for (p = 1; p < numPoints && joinSize; ++p) {
2545:       PetscInt newJoinSize = 0;

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

2551:         for (m = 0; m < joinSize; ++m) {
2552:           if (point == join[i][m]) {
2553:             join[1-i][newJoinSize++] = point;
2554:             break;
2555:           }
2556:         }
2557:       }
2558:       joinSize = newJoinSize;
2559:       i        = 1-i;
2560:     }
2561:     if (joinSize) break;
2562:   }
2563:   *numCoveredPoints = joinSize;
2564:   *coveredPoints    = join[i];
2565:   for (p = 0; p < numPoints; ++p) {
2566:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
2567:   }
2568:   PetscFree(closures);
2569:   DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);
2570:   DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);
2571:   return(0);
2572: }

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

2577:   Not Collective

2579:   Input Parameters:
2580: + dm - The DMPlex object
2581: . numPoints - The number of input points for the meet
2582: - points - The input points

2584:   Output Parameters:
2585: + numCoveredPoints - The number of points in the meet
2586: - coveredPoints - The points in the meet

2588:   Level: intermediate

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

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

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

2598: .keywords: mesh
2599: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2600: @*/
2601: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2602: {
2603:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2604:   PetscInt      *meet[2];
2605:   PetscInt       meetSize, i = 0;
2606:   PetscInt       dof, off, p, c, m;

2614:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);
2615:   DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);
2616:   /* Copy in cone of first point */
2617:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
2618:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
2619:   for (meetSize = 0; meetSize < dof; ++meetSize) {
2620:     meet[i][meetSize] = mesh->cones[off+meetSize];
2621:   }
2622:   /* Check each successive cone */
2623:   for (p = 1; p < numPoints; ++p) {
2624:     PetscInt newMeetSize = 0;

2626:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
2627:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
2628:     for (c = 0; c < dof; ++c) {
2629:       const PetscInt point = mesh->cones[off+c];

2631:       for (m = 0; m < meetSize; ++m) {
2632:         if (point == meet[i][m]) {
2633:           meet[1-i][newMeetSize++] = point;
2634:           break;
2635:         }
2636:       }
2637:     }
2638:     meetSize = newMeetSize;
2639:     i        = 1-i;
2640:   }
2641:   *numCoveringPoints = meetSize;
2642:   *coveringPoints    = meet[i];
2643:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2644:   return(0);
2645: }

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

2650:   Not Collective

2652:   Input Parameters:
2653: + dm - The DMPlex object
2654: . numPoints - The number of input points for the meet
2655: - points - The input points

2657:   Output Parameters:
2658: + numCoveredPoints - The number of points in the meet
2659: - coveredPoints - The points in the meet

2661:   Level: intermediate

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

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

2669: .keywords: mesh
2670: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2671: @*/
2672: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2673: {

2681:   DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);
2682:   if (numCoveredPoints) *numCoveredPoints = 0;
2683:   return(0);
2684: }

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

2689:   Not Collective

2691:   Input Parameters:
2692: + dm - The DMPlex object
2693: . numPoints - The number of input points for the meet
2694: - points - The input points

2696:   Output Parameters:
2697: + numCoveredPoints - The number of points in the meet
2698: - coveredPoints - The points in the meet

2700:   Level: intermediate

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

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

2708: .keywords: mesh
2709: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2710: @*/
2711: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2712: {
2713:   DM_Plex       *mesh = (DM_Plex*) dm->data;
2714:   PetscInt      *offsets, **closures;
2715:   PetscInt      *meet[2];
2716:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2717:   PetscInt       p, h, c, m, mc;


2726:   DMPlexGetDepth(dm, &height);
2727:   PetscMalloc1(numPoints, &closures);
2728:   DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2729:   mc      = mesh->maxConeSize;
2730:   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2731:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);
2732:   DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);

2734:   for (p = 0; p < numPoints; ++p) {
2735:     PetscInt closureSize;

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

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

2743:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
2744:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2745:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2746:           offsets[p*(height+2)+h+1] = i;
2747:           break;
2748:         }
2749:       }
2750:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2751:     }
2752:     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);
2753:   }
2754:   for (h = 0; h < height+1; ++h) {
2755:     PetscInt dof;

2757:     /* Copy in cone of first point */
2758:     dof = offsets[h+1] - offsets[h];
2759:     for (meetSize = 0; meetSize < dof; ++meetSize) {
2760:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2761:     }
2762:     /* Check each successive cone */
2763:     for (p = 1; p < numPoints && meetSize; ++p) {
2764:       PetscInt newMeetSize = 0;

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

2770:         for (m = 0; m < meetSize; ++m) {
2771:           if (point == meet[i][m]) {
2772:             meet[1-i][newMeetSize++] = point;
2773:             break;
2774:           }
2775:         }
2776:       }
2777:       meetSize = newMeetSize;
2778:       i        = 1-i;
2779:     }
2780:     if (meetSize) break;
2781:   }
2782:   *numCoveredPoints = meetSize;
2783:   *coveredPoints    = meet[i];
2784:   for (p = 0; p < numPoints; ++p) {
2785:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2786:   }
2787:   PetscFree(closures);
2788:   DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);
2789:   DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);
2790:   return(0);
2791: }

2793: /*@C
2794:   DMPlexEqual - Determine if two DMs have the same topology

2796:   Not Collective

2798:   Input Parameters:
2799: + dmA - A DMPlex object
2800: - dmB - A DMPlex object

2802:   Output Parameters:
2803: . equal - PETSC_TRUE if the topologies are identical

2805:   Level: intermediate

2807:   Notes:
2808:   We are not solving graph isomorphism, so we do not permutation.

2810: .keywords: mesh
2811: .seealso: DMPlexGetCone()
2812: @*/
2813: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2814: {
2815:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


2823:   *equal = PETSC_FALSE;
2824:   DMPlexGetDepth(dmA, &depth);
2825:   DMPlexGetDepth(dmB, &depthB);
2826:   if (depth != depthB) return(0);
2827:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2828:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2829:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2830:   for (p = pStart; p < pEnd; ++p) {
2831:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2832:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

2834:     DMPlexGetConeSize(dmA, p, &coneSize);
2835:     DMPlexGetCone(dmA, p, &cone);
2836:     DMPlexGetConeOrientation(dmA, p, &ornt);
2837:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2838:     DMPlexGetCone(dmB, p, &coneB);
2839:     DMPlexGetConeOrientation(dmB, p, &orntB);
2840:     if (coneSize != coneSizeB) return(0);
2841:     for (c = 0; c < coneSize; ++c) {
2842:       if (cone[c] != coneB[c]) return(0);
2843:       if (ornt[c] != orntB[c]) return(0);
2844:     }
2845:     DMPlexGetSupportSize(dmA, p, &supportSize);
2846:     DMPlexGetSupport(dmA, p, &support);
2847:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2848:     DMPlexGetSupport(dmB, p, &supportB);
2849:     if (supportSize != supportSizeB) return(0);
2850:     for (s = 0; s < supportSize; ++s) {
2851:       if (support[s] != supportB[s]) return(0);
2852:     }
2853:   }
2854:   *equal = PETSC_TRUE;
2855:   return(0);
2856: }

2858: /*@C
2859:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

2861:   Not Collective

2863:   Input Parameters:
2864: + dm         - The DMPlex
2865: . cellDim    - The cell dimension
2866: - numCorners - The number of vertices on a cell

2868:   Output Parameters:
2869: . numFaceVertices - The number of vertices on a face

2871:   Level: developer

2873:   Notes:
2874:   Of course this can only work for a restricted set of symmetric shapes

2876: .seealso: DMPlexGetCone()
2877: @*/
2878: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2879: {
2880:   MPI_Comm       comm;

2884:   PetscObjectGetComm((PetscObject)dm,&comm);
2886:   switch (cellDim) {
2887:   case 0:
2888:     *numFaceVertices = 0;
2889:     break;
2890:   case 1:
2891:     *numFaceVertices = 1;
2892:     break;
2893:   case 2:
2894:     switch (numCorners) {
2895:     case 3: /* triangle */
2896:       *numFaceVertices = 2; /* Edge has 2 vertices */
2897:       break;
2898:     case 4: /* quadrilateral */
2899:       *numFaceVertices = 2; /* Edge has 2 vertices */
2900:       break;
2901:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2902:       *numFaceVertices = 3; /* Edge has 3 vertices */
2903:       break;
2904:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2905:       *numFaceVertices = 3; /* Edge has 3 vertices */
2906:       break;
2907:     default:
2908:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2909:     }
2910:     break;
2911:   case 3:
2912:     switch (numCorners) {
2913:     case 4: /* tetradehdron */
2914:       *numFaceVertices = 3; /* Face has 3 vertices */
2915:       break;
2916:     case 6: /* tet cohesive cells */
2917:       *numFaceVertices = 4; /* Face has 4 vertices */
2918:       break;
2919:     case 8: /* hexahedron */
2920:       *numFaceVertices = 4; /* Face has 4 vertices */
2921:       break;
2922:     case 9: /* tet cohesive Lagrange cells */
2923:       *numFaceVertices = 6; /* Face has 6 vertices */
2924:       break;
2925:     case 10: /* quadratic tetrahedron */
2926:       *numFaceVertices = 6; /* Face has 6 vertices */
2927:       break;
2928:     case 12: /* hex cohesive Lagrange cells */
2929:       *numFaceVertices = 6; /* Face has 6 vertices */
2930:       break;
2931:     case 18: /* quadratic tet cohesive Lagrange cells */
2932:       *numFaceVertices = 6; /* Face has 6 vertices */
2933:       break;
2934:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2935:       *numFaceVertices = 9; /* Face has 9 vertices */
2936:       break;
2937:     default:
2938:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2939:     }
2940:     break;
2941:   default:
2942:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
2943:   }
2944:   return(0);
2945: }

2947: /*@
2948:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

2950:   Not Collective

2952:   Input Parameter:
2953: . dm    - The DMPlex object

2955:   Output Parameter:
2956: . depthLabel - The DMLabel recording point depth

2958:   Level: developer

2960: .keywords: mesh, points
2961: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2962: @*/
2963: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2964: {

2970:   if (!dm->depthLabel) {DMGetLabel(dm, "depth", &dm->depthLabel);}
2971:   *depthLabel = dm->depthLabel;
2972:   return(0);
2973: }

2975: /*@
2976:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

2978:   Not Collective

2980:   Input Parameter:
2981: . dm    - The DMPlex object

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

2986:   Level: developer

2988: .keywords: mesh, points
2989: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2990: @*/
2991: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
2992: {
2993:   DMLabel        label;
2994:   PetscInt       d = 0;

3000:   DMPlexGetDepthLabel(dm, &label);
3001:   if (label) {DMLabelGetNumValues(label, &d);}
3002:   *depth = d-1;
3003:   return(0);
3004: }

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

3009:   Not Collective

3011:   Input Parameters:
3012: + dm           - The DMPlex object
3013: - stratumValue - The requested depth

3015:   Output Parameters:
3016: + start - The first point at this depth
3017: - end   - One beyond the last point at this depth

3019:   Level: developer

3021: .keywords: mesh, points
3022: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3023: @*/
3024: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3025: {
3026:   DMLabel        label;
3027:   PetscInt       pStart, pEnd;

3034:   DMPlexGetChart(dm, &pStart, &pEnd);
3035:   if (pStart == pEnd) return(0);
3036:   if (stratumValue < 0) {
3037:     if (start) *start = pStart;
3038:     if (end)   *end   = pEnd;
3039:     return(0);
3040:   }
3041:   DMPlexGetDepthLabel(dm, &label);
3042:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3043:   DMLabelGetStratumBounds(label, stratumValue, start, end);
3044:   return(0);
3045: }

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

3050:   Not Collective

3052:   Input Parameters:
3053: + dm           - The DMPlex object
3054: - stratumValue - The requested height

3056:   Output Parameters:
3057: + start - The first point at this height
3058: - end   - One beyond the last point at this height

3060:   Level: developer

3062: .keywords: mesh, points
3063: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3064: @*/
3065: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3066: {
3067:   DMLabel        label;
3068:   PetscInt       depth, pStart, pEnd;

3075:   DMPlexGetChart(dm, &pStart, &pEnd);
3076:   if (pStart == pEnd) return(0);
3077:   if (stratumValue < 0) {
3078:     if (start) *start = pStart;
3079:     if (end)   *end   = pEnd;
3080:     return(0);
3081:   }
3082:   DMPlexGetDepthLabel(dm, &label);
3083:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3084:   DMLabelGetNumValues(label, &depth);
3085:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
3086:   return(0);
3087: }

3089: /* Set the number of dof on each point and separate by fields */
3090: static PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3091: {
3092:   PetscInt      *pMax;
3093:   PetscInt       depth, cellHeight, pStart = 0, pEnd = 0;
3094:   PetscInt       Nf, p, d, dep, f;
3095:   PetscBool     *isFE;

3099:   PetscMalloc1(numFields, &isFE);
3100:   DMGetNumFields(dm, &Nf);
3101:   for (f = 0; f < numFields; ++f) {
3102:     PetscObject  obj;
3103:     PetscClassId id;

3105:     isFE[f] = PETSC_FALSE;
3106:     if (f >= Nf) continue;
3107:     DMGetField(dm, f, &obj);
3108:     PetscObjectGetClassId(obj, &id);
3109:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
3110:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3111:   }
3112:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
3113:   if (numFields > 0) {
3114:     PetscSectionSetNumFields(*section, numFields);
3115:     if (numComp) {
3116:       for (f = 0; f < numFields; ++f) {
3117:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
3118:         if (isFE[f]) {
3119:           PetscFE           fe;
3120:           PetscDualSpace    dspace;
3121:           const PetscInt    ***perms;
3122:           const PetscScalar ***flips;
3123:           const PetscInt    *numDof;

3125:           DMGetField(dm,f,(PetscObject *) &fe);
3126:           PetscFEGetDualSpace(fe,&dspace);
3127:           PetscDualSpaceGetSymmetries(dspace,&perms,&flips);
3128:           PetscDualSpaceGetNumDof(dspace,&numDof);
3129:           if (perms || flips) {
3130:             DM               K;
3131:             DMLabel          depthLabel;
3132:             PetscInt         depth, h;
3133:             PetscSectionSym  sym;

3135:             PetscDualSpaceGetDM(dspace,&K);
3136:             DMPlexGetDepthLabel(dm,&depthLabel);
3137:             DMPlexGetDepth(dm,&depth);
3138:             PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);
3139:             for (h = 0; h <= depth; h++) {
3140:               PetscDualSpace    hspace;
3141:               PetscInt          kStart, kEnd;
3142:               PetscInt          kConeSize;
3143:               const PetscInt    **perms0 = NULL;
3144:               const PetscScalar **flips0 = NULL;

3146:               PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);
3147:               DMPlexGetHeightStratum(K,h,&kStart,&kEnd);
3148:               if (!hspace) continue;
3149:               PetscDualSpaceGetSymmetries(hspace,&perms,&flips);
3150:               if (perms) perms0 = perms[0];
3151:               if (flips) flips0 = flips[0];
3152:               if (!(perms0 || flips0)) continue;
3153:               DMPlexGetConeSize(K,kStart,&kConeSize);
3154:               PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);
3155:             }
3156:             PetscSectionSetFieldSym(*section,f,sym);
3157:             PetscSectionSymDestroy(&sym);
3158:           }
3159:         }
3160:       }
3161:     }
3162:   }
3163:   DMPlexGetChart(dm, &pStart, &pEnd);
3164:   PetscSectionSetChart(*section, pStart, pEnd);
3165:   DMPlexGetDepth(dm, &depth);
3166:   PetscMalloc1(depth+1,&pMax);
3167:   DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
3168:   DMPlexGetVTKCellHeight(dm, &cellHeight);
3169:   for (dep = 0; dep <= depth - cellHeight; ++dep) {
3170:     d    = dim == depth ? dep : (!dep ? 0 : dim);
3171:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
3172:     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
3173:     for (p = pStart; p < pEnd; ++p) {
3174:       PetscInt tot = 0;

3176:       for (f = 0; f < numFields; ++f) {
3177:         if (isFE[f] && p >= pMax[dep]) continue;
3178:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
3179:         tot += numDof[f*(dim+1)+d];
3180:       }
3181:       PetscSectionSetDof(*section, p, tot);
3182:     }
3183:   }
3184:   PetscFree(pMax);
3185:   PetscFree(isFE);
3186:   return(0);
3187: }

3189: /* Set the number of dof on each point and separate by fields
3190:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3191: */
3192: static PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3193: {
3194:   PetscInt       numFields;
3195:   PetscInt       bc;
3196:   PetscSection   aSec;

3200:   PetscSectionGetNumFields(section, &numFields);
3201:   for (bc = 0; bc < numBC; ++bc) {
3202:     PetscInt        field = 0;
3203:     const PetscInt *comp;
3204:     const PetscInt *idx;
3205:     PetscInt        Nc = -1, n, i;

3207:     if (numFields) field = bcField[bc];
3208:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3209:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3210:     ISGetLocalSize(bcPoints[bc], &n);
3211:     ISGetIndices(bcPoints[bc], &idx);
3212:     for (i = 0; i < n; ++i) {
3213:       const PetscInt p = idx[i];
3214:       PetscInt       numConst;

3216:       if (numFields) {
3217:         PetscSectionGetFieldDof(section, p, field, &numConst);
3218:       } else {
3219:         PetscSectionGetDof(section, p, &numConst);
3220:       }
3221:       /* If Nc < 0, constrain every dof on the point */
3222:       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3223:       if (numFields) {PetscSectionAddFieldConstraintDof(section, p, field, numConst);}
3224:       PetscSectionAddConstraintDof(section, p, numConst);
3225:     }
3226:     ISRestoreIndices(bcPoints[bc], &idx);
3227:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3228:   }
3229:   DMPlexGetAnchors(dm, &aSec, NULL);
3230:   if (aSec) {
3231:     PetscInt aStart, aEnd, a;

3233:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3234:     for (a = aStart; a < aEnd; a++) {
3235:       PetscInt dof, f;

3237:       PetscSectionGetDof(aSec, a, &dof);
3238:       if (dof) {
3239:         /* if there are point-to-point constraints, then all dofs are constrained */
3240:         PetscSectionGetDof(section, a, &dof);
3241:         PetscSectionSetConstraintDof(section, a, dof);
3242:         for (f = 0; f < numFields; f++) {
3243:           PetscSectionGetFieldDof(section, a, f, &dof);
3244:           PetscSectionSetFieldConstraintDof(section, a, f, dof);
3245:         }
3246:       }
3247:     }
3248:   }
3249:   return(0);
3250: }

3252: /* Set the constrained field indices on each point
3253:    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3254: */
3255: static PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3256: {
3257:   PetscSection   aSec;
3258:   PetscInt      *indices;
3259:   PetscInt       numFields, cdof, maxDof = 0, pStart, pEnd, p, bc, f, d;

3263:   PetscSectionGetNumFields(section, &numFields);
3264:   if (!numFields) return(0);
3265:   /* Initialize all field indices to -1 */
3266:   PetscSectionGetChart(section, &pStart, &pEnd);
3267:   for (p = pStart; p < pEnd; ++p) {PetscSectionGetConstraintDof(section, p, &cdof); maxDof = PetscMax(maxDof, cdof);}
3268:   PetscMalloc1(maxDof, &indices);
3269:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3270:   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {PetscSectionSetFieldConstraintIndices(section, p, f, indices);}
3271:   /* Handle BC constraints */
3272:   for (bc = 0; bc < numBC; ++bc) {
3273:     const PetscInt  field = bcField[bc];
3274:     const PetscInt *comp, *idx;
3275:     PetscInt        Nc = -1, n, i;

3277:     if (bcComps && bcComps[bc]) {ISGetLocalSize(bcComps[bc], &Nc);}
3278:     if (bcComps && bcComps[bc]) {ISGetIndices(bcComps[bc], &comp);}
3279:     ISGetLocalSize(bcPoints[bc], &n);
3280:     ISGetIndices(bcPoints[bc], &idx);
3281:     for (i = 0; i < n; ++i) {
3282:       const PetscInt  p = idx[i];
3283:       const PetscInt *find;
3284:       PetscInt        fdof, fcdof, c;

3286:       PetscSectionGetFieldDof(section, p, field, &fdof);
3287:       if (!fdof) continue;
3288:       if (Nc < 0) {
3289:         for (d = 0; d < fdof; ++d) indices[d] = d;
3290:         fcdof = fdof;
3291:       } else {
3292:         PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);
3293:         PetscSectionGetFieldConstraintIndices(section, p, field, &find);
3294:         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3295:         for (c = 0; c < Nc; ++c) indices[d++] = comp[c];
3296:         PetscSortRemoveDupsInt(&d, indices);
3297:         for (c = d; c < fcdof; ++c) indices[c] = -1;
3298:         fcdof = d;
3299:       }
3300:       PetscSectionSetFieldConstraintDof(section, p, field, fcdof);
3301:       PetscSectionSetFieldConstraintIndices(section, p, field, indices);
3302:     }
3303:     if (bcComps && bcComps[bc]) {ISRestoreIndices(bcComps[bc], &comp);}
3304:     ISRestoreIndices(bcPoints[bc], &idx);
3305:   }
3306:   /* Handle anchors */
3307:   DMPlexGetAnchors(dm, &aSec, NULL);
3308:   if (aSec) {
3309:     PetscInt aStart, aEnd, a;

3311:     for (d = 0; d < maxDof; ++d) indices[d] = d;
3312:     PetscSectionGetChart(aSec, &aStart, &aEnd);
3313:     for (a = aStart; a < aEnd; a++) {
3314:       PetscInt dof, f;

3316:       PetscSectionGetDof(aSec, a, &dof);
3317:       if (dof) {
3318:         /* if there are point-to-point constraints, then all dofs are constrained */
3319:         for (f = 0; f < numFields; f++) {
3320:           PetscSectionSetFieldConstraintIndices(section, a, f, indices);
3321:         }
3322:       }
3323:     }
3324:   }
3325:   PetscFree(indices);
3326:   return(0);
3327: }

3329: /* Set the constrained indices on each point */
3330: static PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3331: {
3332:   PetscInt      *indices;
3333:   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;

3337:   PetscSectionGetNumFields(section, &numFields);
3338:   PetscSectionGetMaxDof(section, &maxDof);
3339:   PetscSectionGetChart(section, &pStart, &pEnd);
3340:   PetscMalloc1(maxDof, &indices);
3341:   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3342:   for (p = pStart; p < pEnd; ++p) {
3343:     PetscInt cdof, d;

3345:     PetscSectionGetConstraintDof(section, p, &cdof);
3346:     if (cdof) {
3347:       if (numFields) {
3348:         PetscInt numConst = 0, foff = 0;

3350:         for (f = 0; f < numFields; ++f) {
3351:           const PetscInt *find;
3352:           PetscInt        fcdof, fdof;

3354:           PetscSectionGetFieldDof(section, p, f, &fdof);
3355:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
3356:           /* Change constraint numbering from field component to local dof number */
3357:           PetscSectionGetFieldConstraintIndices(section, p, f, &find);
3358:           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3359:           numConst += fcdof;
3360:           foff     += fdof;
3361:         }
3362:         if (cdof != numConst) {PetscSectionSetConstraintDof(section, p, numConst);}
3363:       } else {
3364:         for (d = 0; d < cdof; ++d) indices[d] = d;
3365:       }
3366:       PetscSectionSetConstraintIndices(section, p, indices);
3367:     }
3368:   }
3369:   PetscFree(indices);
3370:   return(0);
3371: }

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

3376:   Not Collective

3378:   Input Parameters:
3379: + dm        - The DMPlex object
3380: . dim       - The spatial dimension of the problem
3381: . numFields - The number of fields in the problem
3382: . numComp   - An array of size numFields that holds the number of components for each field
3383: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3384: . numBC     - The number of boundary conditions
3385: . bcField   - An array of size numBC giving the field number for each boundry condition
3386: . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3387: . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3388: - perm      - Optional permutation of the chart, or NULL

3390:   Output Parameter:
3391: . section - The PetscSection object

3393:   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
3394:   number of dof for field 0 on each edge.

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

3398:   Level: developer

3400:   Fortran Notes:
3401:   A Fortran 90 version is available as DMPlexCreateSectionF90()

3403: .keywords: mesh, elements
3404: .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3405: @*/
3406: 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)
3407: {
3408:   PetscSection   aSec;

3412:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
3413:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);
3414:   if (perm) {PetscSectionSetPermutation(*section, perm);}
3415:   PetscSectionSetUp(*section);
3416:   DMPlexGetAnchors(dm,&aSec,NULL);
3417:   if (numBC || aSec) {
3418:     DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);
3419:     DMPlexCreateSectionBCIndices(dm, *section);
3420:   }
3421:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
3422:   return(0);
3423: }

3425: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3426: {
3427:   PetscSection   section, s;
3428:   Mat            m;
3429:   PetscInt       maxHeight;

3433:   DMClone(dm, cdm);
3434:   DMPlexGetMaxProjectionHeight(dm, &maxHeight);
3435:   DMPlexSetMaxProjectionHeight(*cdm, maxHeight);
3436:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
3437:   DMSetDefaultSection(*cdm, section);
3438:   PetscSectionDestroy(&section);
3439:   PetscSectionCreate(PETSC_COMM_SELF, &s);
3440:   MatCreate(PETSC_COMM_SELF, &m);
3441:   DMSetDefaultConstraints(*cdm, s, m);
3442:   PetscSectionDestroy(&s);
3443:   MatDestroy(&m);
3444:   return(0);
3445: }

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

3450:   Not Collective

3452:   Input Parameters:
3453: . dm        - The DMPlex object

3455:   Output Parameter:
3456: . section - The PetscSection object

3458:   Level: developer

3460: .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3461: @*/
3462: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3463: {
3464:   DM_Plex *mesh = (DM_Plex*) dm->data;

3468:   if (section) *section = mesh->coneSection;
3469:   return(0);
3470: }

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

3475:   Not Collective

3477:   Input Parameters:
3478: . dm        - The DMPlex object

3480:   Output Parameter:
3481: . section - The PetscSection object

3483:   Level: developer

3485: .seealso: DMPlexGetConeSection()
3486: @*/
3487: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3488: {
3489:   DM_Plex *mesh = (DM_Plex*) dm->data;

3493:   if (section) *section = mesh->supportSection;
3494:   return(0);
3495: }

3497: /*@C
3498:   DMPlexGetCones - Return cone data

3500:   Not Collective

3502:   Input Parameters:
3503: . dm        - The DMPlex object

3505:   Output Parameter:
3506: . cones - The cone for each point

3508:   Level: developer

3510: .seealso: DMPlexGetConeSection()
3511: @*/
3512: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3513: {
3514:   DM_Plex *mesh = (DM_Plex*) dm->data;

3518:   if (cones) *cones = mesh->cones;
3519:   return(0);
3520: }

3522: /*@C
3523:   DMPlexGetConeOrientations - Return cone orientation data

3525:   Not Collective

3527:   Input Parameters:
3528: . dm        - The DMPlex object

3530:   Output Parameter:
3531: . coneOrientations - The cone orientation for each point

3533:   Level: developer

3535: .seealso: DMPlexGetConeSection()
3536: @*/
3537: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3538: {
3539:   DM_Plex *mesh = (DM_Plex*) dm->data;

3543:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3544:   return(0);
3545: }

3547: /******************************** FEM Support **********************************/

3549: PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscInt point, PetscSection section)
3550: {
3551:   DMLabel        label;
3552:   PetscInt      *perm;
3553:   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;

3557:   if (point < 0) {DMPlexGetDepthStratum(dm, 1, &point, NULL);}
3558:   DMGetDimension(dm, &dim);
3559:   DMPlexGetDepthLabel(dm, &label);
3560:   DMLabelGetValue(label, point, &depth);
3561:   if (depth == 1) {eStart = point;}
3562:   else if  (depth == dim) {
3563:     const PetscInt *cone;

3565:     DMPlexGetCone(dm, point, &cone);
3566:     eStart = cone[0];
3567:   } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering", point, depth);
3568:   if (!section) {DMGetDefaultSection(dm, &section);}
3569:   PetscSectionGetNumFields(section, &Nf);
3570:   if (dim <= 1) return(0);
3571:   for (f = 0; f < Nf; ++f) {
3572:     /* An order k SEM disc has k-1 dofs on an edge */
3573:     PetscSectionGetFieldDof(section, eStart, f, &k);
3574:     PetscSectionGetFieldComponents(section, f, &Nc);
3575:     k = k/Nc + 1;
3576:     size += PetscPowInt(k+1, dim)*Nc;
3577:   }
3578:   PetscMalloc1(size, &perm);
3579:   for (f = 0; f < Nf; ++f) {
3580:     switch (dim) {
3581:     case 2:
3582:       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3583:       PetscSectionGetFieldDof(section, eStart, f, &k);
3584:       PetscSectionGetFieldComponents(section, f, &Nc);
3585:       k = k/Nc + 1;
3586:       /* The SEM order is

3588:          v_lb, {e_b}, v_rb,
3589:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3590:          v_lt, reverse {e_t}, v_rt
3591:       */
3592:       {
3593:         const PetscInt of   = 0;
3594:         const PetscInt oeb  = of   + PetscSqr(k-1);
3595:         const PetscInt oer  = oeb  + (k-1);
3596:         const PetscInt oet  = oer  + (k-1);
3597:         const PetscInt oel  = oet  + (k-1);
3598:         const PetscInt ovlb = oel  + (k-1);
3599:         const PetscInt ovrb = ovlb + 1;
3600:         const PetscInt ovrt = ovrb + 1;
3601:         const PetscInt ovlt = ovrt + 1;
3602:         PetscInt       o;

3604:         /* bottom */
3605:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3606:         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3607:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3608:         /* middle */
3609:         for (i = 0; i < k-1; ++i) {
3610:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3611:           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;
3612:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3613:         }
3614:         /* top */
3615:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3616:         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3617:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3618:         foffset = offset;
3619:       }
3620:       break;
3621:     case 3:
3622:       /* The original hex closure is

3624:          {c,
3625:           f_b, f_t, f_f, f_b, f_r, f_l,
3626:           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3627:           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3628:       */
3629:       PetscSectionGetFieldDof(section, eStart, f, &k);
3630:       PetscSectionGetFieldComponents(section, f, &Nc);
3631:       k = k/Nc + 1;
3632:       /* The SEM order is
3633:          Bottom Slice
3634:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3635:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3636:          v_blb, {e_bb}, v_brb,

3638:          Middle Slice (j)
3639:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3640:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3641:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

3643:          Top Slice
3644:          v_tlf, {e_tf}, v_trf,
3645:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3646:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3647:       */
3648:       {
3649:         const PetscInt oc    = 0;
3650:         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3651:         const PetscInt oft   = ofb   + PetscSqr(k-1);
3652:         const PetscInt off   = oft   + PetscSqr(k-1);
3653:         const PetscInt ofk   = off   + PetscSqr(k-1);
3654:         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3655:         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3656:         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3657:         const PetscInt oebb  = oebl  + (k-1);
3658:         const PetscInt oebr  = oebb  + (k-1);
3659:         const PetscInt oebf  = oebr  + (k-1);
3660:         const PetscInt oetf  = oebf  + (k-1);
3661:         const PetscInt oetr  = oetf  + (k-1);
3662:         const PetscInt oetb  = oetr  + (k-1);
3663:         const PetscInt oetl  = oetb  + (k-1);
3664:         const PetscInt oerf  = oetl  + (k-1);
3665:         const PetscInt oelf  = oerf  + (k-1);
3666:         const PetscInt oelb  = oelf  + (k-1);
3667:         const PetscInt oerb  = oelb  + (k-1);
3668:         const PetscInt ovblf = oerb  + (k-1);
3669:         const PetscInt ovblb = ovblf + 1;
3670:         const PetscInt ovbrb = ovblb + 1;
3671:         const PetscInt ovbrf = ovbrb + 1;
3672:         const PetscInt ovtlf = ovbrf + 1;
3673:         const PetscInt ovtrf = ovtlf + 1;
3674:         const PetscInt ovtrb = ovtrf + 1;
3675:         const PetscInt ovtlb = ovtrb + 1;
3676:         PetscInt       o, n;

3678:         /* Bottom Slice */
3679:         /*   bottom */
3680:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3681:         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3682:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3683:         /*   middle */
3684:         for (i = 0; i < k-1; ++i) {
3685:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3686:           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;}
3687:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3688:         }
3689:         /*   top */
3690:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3691:         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3692:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;

3694:         /* Middle Slice */
3695:         for (j = 0; j < k-1; ++j) {
3696:           /*   bottom */
3697:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3698:           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;
3699:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3700:           /*   middle */
3701:           for (i = 0; i < k-1; ++i) {
3702:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3703:             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;
3704:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3705:           }
3706:           /*   top */
3707:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3708:           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;
3709:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3710:         }

3712:         /* Top Slice */
3713:         /*   bottom */
3714:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3715:         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3716:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3717:         /*   middle */
3718:         for (i = 0; i < k-1; ++i) {
3719:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3720:           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3721:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3722:         }
3723:         /*   top */
3724:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3725:         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3726:         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;

3728:         foffset = offset;
3729:       }
3730:       break;
3731:     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3732:     }
3733:   }
3734:   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3735:   /* Check permutation */
3736:   {
3737:     PetscInt *check;

3739:     PetscMalloc1(size, &check);
3740:     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]);}
3741:     for (i = 0; i < size; ++i) check[perm[i]] = i;
3742:     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3743:     PetscFree(check);
3744:   }
3745:   PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);
3746:   return(0);
3747: }

3749: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3750: {
3751:   PetscDS        prob;
3752:   PetscInt       depth, Nf, h;
3753:   DMLabel        label;

3757:   prob    = dm->prob;
3758:   Nf      = prob->Nf;
3759:   label   = dm->depthLabel;
3760:   *dspace = NULL;
3761:   if (field < Nf) {
3762:     PetscObject disc = prob->disc[field];

3764:     if (disc->classid == PETSCFE_CLASSID) {
3765:       PetscDualSpace dsp;

3767:       PetscFEGetDualSpace((PetscFE)disc,&dsp);
3768:       DMLabelGetNumValues(label,&depth);
3769:       DMLabelGetValue(label,point,&h);
3770:       h    = depth - 1 - h;
3771:       if (h) {
3772:         PetscDualSpaceGetHeightSubspace(dsp,h,dspace);
3773:       } else {
3774:         *dspace = dsp;
3775:       }
3776:     }
3777:   }
3778:   return(0);
3779: }


3782: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3783: {
3784:   PetscScalar    *array, *vArray;
3785:   const PetscInt *cone, *coneO;
3786:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3787:   PetscErrorCode  ierr;

3790:   PetscSectionGetChart(section, &pStart, &pEnd);
3791:   DMPlexGetConeSize(dm, point, &numPoints);
3792:   DMPlexGetCone(dm, point, &cone);
3793:   DMPlexGetConeOrientation(dm, point, &coneO);
3794:   if (!values || !*values) {
3795:     if ((point >= pStart) && (point < pEnd)) {
3796:       PetscInt dof;

3798:       PetscSectionGetDof(section, point, &dof);
3799:       size += dof;
3800:     }
3801:     for (p = 0; p < numPoints; ++p) {
3802:       const PetscInt cp = cone[p];
3803:       PetscInt       dof;

3805:       if ((cp < pStart) || (cp >= pEnd)) continue;
3806:       PetscSectionGetDof(section, cp, &dof);
3807:       size += dof;
3808:     }
3809:     if (!values) {
3810:       if (csize) *csize = size;
3811:       return(0);
3812:     }
3813:     DMGetWorkArray(dm, size, MPIU_SCALAR, &array);
3814:   } else {
3815:     array = *values;
3816:   }
3817:   size = 0;
3818:   VecGetArray(v, &vArray);
3819:   if ((point >= pStart) && (point < pEnd)) {
3820:     PetscInt     dof, off, d;
3821:     PetscScalar *varr;

3823:     PetscSectionGetDof(section, point, &dof);
3824:     PetscSectionGetOffset(section, point, &off);
3825:     varr = &vArray[off];
3826:     for (d = 0; d < dof; ++d, ++offset) {
3827:       array[offset] = varr[d];
3828:     }
3829:     size += dof;
3830:   }
3831:   for (p = 0; p < numPoints; ++p) {
3832:     const PetscInt cp = cone[p];
3833:     PetscInt       o  = coneO[p];
3834:     PetscInt       dof, off, d;
3835:     PetscScalar   *varr;

3837:     if ((cp < pStart) || (cp >= pEnd)) continue;
3838:     PetscSectionGetDof(section, cp, &dof);
3839:     PetscSectionGetOffset(section, cp, &off);
3840:     varr = &vArray[off];
3841:     if (o >= 0) {
3842:       for (d = 0; d < dof; ++d, ++offset) {
3843:         array[offset] = varr[d];
3844:       }
3845:     } else {
3846:       for (d = dof-1; d >= 0; --d, ++offset) {
3847:         array[offset] = varr[d];
3848:       }
3849:     }
3850:     size += dof;
3851:   }
3852:   VecRestoreArray(v, &vArray);
3853:   if (!*values) {
3854:     if (csize) *csize = size;
3855:     *values = array;
3856:   } else {
3857:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3858:     *csize = size;
3859:   }
3860:   return(0);
3861: }

3863: static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
3864: {
3865:   const PetscInt *cla;
3866:   PetscInt       np, *pts = NULL;

3870:   PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);
3871:   if (!*clPoints) {
3872:     PetscInt pStart, pEnd, p, q;

3874:     PetscSectionGetChart(section, &pStart, &pEnd);
3875:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);
3876:     /* Compress out points not in the section */
3877:     for (p = 0, q = 0; p < np; p++) {
3878:       PetscInt r = pts[2*p];
3879:       if ((r >= pStart) && (r < pEnd)) {
3880:         pts[q*2]   = r;
3881:         pts[q*2+1] = pts[2*p+1];
3882:         ++q;
3883:       }
3884:     }
3885:     np = q;
3886:     cla = NULL;
3887:   } else {
3888:     PetscInt dof, off;

3890:     PetscSectionGetDof(*clSec, point, &dof);
3891:     PetscSectionGetOffset(*clSec, point, &off);
3892:     ISGetIndices(*clPoints, &cla);
3893:     np   = dof/2;
3894:     pts  = (PetscInt *) &cla[off];
3895:   }
3896:   *numPoints = np;
3897:   *points    = pts;
3898:   *clp       = cla;

3900:   return(0);
3901: }

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

3908:   if (!*clPoints) {
3909:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);
3910:   } else {
3911:     ISRestoreIndices(*clPoints, clp);
3912:   }
3913:   *numPoints = 0;
3914:   *points    = NULL;
3915:   *clSec     = NULL;
3916:   *clPoints  = NULL;
3917:   *clp       = NULL;
3918:   return(0);
3919: }

3921: 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[])
3922: {
3923:   PetscInt          offset = 0, p;
3924:   const PetscInt    **perms = NULL;
3925:   const PetscScalar **flips = NULL;
3926:   PetscErrorCode    ierr;

3929:   *size = 0;
3930:   PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
3931:   for (p = 0; p < numPoints; p++) {
3932:     const PetscInt    point = points[2*p];
3933:     const PetscInt    *perm = perms ? perms[p] : NULL;
3934:     const PetscScalar *flip = flips ? flips[p] : NULL;
3935:     PetscInt          dof, off, d;
3936:     const PetscScalar *varr;

3938:     PetscSectionGetDof(section, point, &dof);
3939:     PetscSectionGetOffset(section, point, &off);
3940:     varr = &vArray[off];
3941:     if (clperm) {
3942:       if (perm) {
3943:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
3944:       } else {
3945:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
3946:       }
3947:       if (flip) {
3948:         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
3949:       }
3950:     } else {
3951:       if (perm) {
3952:         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
3953:       } else {
3954:         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
3955:       }
3956:       if (flip) {
3957:         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
3958:       }
3959:     }
3960:     offset += dof;
3961:   }
3962:   PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
3963:   *size = offset;
3964:   return(0);
3965: }

3967: 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[])
3968: {
3969:   PetscInt          offset = 0, f;
3970:   PetscErrorCode    ierr;

3973:   *size = 0;
3974:   for (f = 0; f < numFields; ++f) {
3975:     PetscInt          p;
3976:     const PetscInt    **perms = NULL;
3977:     const PetscScalar **flips = NULL;

3979:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
3980:     for (p = 0; p < numPoints; p++) {
3981:       const PetscInt    point = points[2*p];
3982:       PetscInt          fdof, foff, b;
3983:       const PetscScalar *varr;
3984:       const PetscInt    *perm = perms ? perms[p] : NULL;
3985:       const PetscScalar *flip = flips ? flips[p] : NULL;

3987:       PetscSectionGetFieldDof(section, point, f, &fdof);
3988:       PetscSectionGetFieldOffset(section, point, f, &foff);
3989:       varr = &vArray[foff];
3990:       if (clperm) {
3991:         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
3992:         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
3993:         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
3994:       } else {
3995:         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
3996:         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
3997:         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
3998:       }
3999:       offset += fdof;
4000:     }
4001:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4002:   }
4003:   *size = offset;
4004:   return(0);
4005: }

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

4010:   Not collective

4012:   Input Parameters:
4013: + dm - The DM
4014: . section - The section describing the layout in v, or NULL to use the default section
4015: . v - The local vector
4016: . point - The point in the DM
4017: . csize - The size of the input values array, or NULL
4018: - values - An array to use for the values, or NULL to have it allocated automatically

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

4024: $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4025: $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4026: $ assembly function, and a user may already have allocated storage for this operation.
4027: $
4028: $ A typical use could be
4029: $
4030: $  values = NULL;
4031: $  DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4032: $  for (cl = 0; cl < clSize; ++cl) {
4033: $    <Compute on closure>
4034: $  }
4035: $  DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);
4036: $
4037: $ or
4038: $
4039: $  PetscMalloc1(clMaxSize, &values);
4040: $  for (p = pStart; p < pEnd; ++p) {
4041: $    clSize = clMaxSize;
4042: $    DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);
4043: $    for (cl = 0; cl < clSize; ++cl) {
4044: $      <Compute on closure>
4045: $    }
4046: $  }
4047: $  PetscFree(values);

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

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

4055:   Level: intermediate

4057: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4058: @*/
4059: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4060: {
4061:   PetscSection       clSection;
4062:   IS                 clPoints;
4063:   PetscScalar       *array;
4064:   const PetscScalar *vArray;
4065:   PetscInt          *points = NULL;
4066:   const PetscInt    *clp, *perm;
4067:   PetscInt           depth, numFields, numPoints, size;
4068:   PetscErrorCode     ierr;

4072:   if (!section) {DMGetDefaultSection(dm, &section);}
4075:   DMPlexGetDepth(dm, &depth);
4076:   PetscSectionGetNumFields(section, &numFields);
4077:   if (depth == 1 && numFields < 2) {
4078:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
4079:     return(0);
4080:   }
4081:   /* Get points */
4082:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4083:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);
4084:   /* Get array */
4085:   if (!values || !*values) {
4086:     PetscInt asize = 0, dof, p;

4088:     for (p = 0; p < numPoints*2; p += 2) {
4089:       PetscSectionGetDof(section, points[p], &dof);
4090:       asize += dof;
4091:     }
4092:     if (!values) {
4093:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4094:       if (csize) *csize = asize;
4095:       return(0);
4096:     }
4097:     DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);
4098:   } else {
4099:     array = *values;
4100:   }
4101:   VecGetArrayRead(v, &vArray);
4102:   /* Get values */
4103:   if (numFields > 0) {DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);}
4104:   else               {DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);}
4105:   /* Cleanup points */
4106:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4107:   /* Cleanup array */
4108:   VecRestoreArrayRead(v, &vArray);
4109:   if (!*values) {
4110:     if (csize) *csize = size;
4111:     *values = array;
4112:   } else {
4113:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4114:     *csize = size;
4115:   }
4116:   return(0);
4117: }

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

4122:   Not collective

4124:   Input Parameters:
4125: + dm - The DM
4126: . section - The section describing the layout in v, or NULL to use the default section
4127: . v - The local vector
4128: . point - The point in the DM
4129: . csize - The number of values in the closure, or NULL
4130: - values - The array of values, which is a borrowed array and should not be freed

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

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

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

4140:   Level: intermediate

4142: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4143: @*/
4144: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4145: {
4146:   PetscInt       size = 0;

4150:   /* Should work without recalculating size */
4151:   DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);
4152:   *values = NULL;
4153:   return(0);
4154: }

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

4159: 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[])
4160: {
4161:   PetscInt        cdof;   /* The number of constraints on this point */
4162:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4163:   PetscScalar    *a;
4164:   PetscInt        off, cind = 0, k;
4165:   PetscErrorCode  ierr;

4168:   PetscSectionGetConstraintDof(section, point, &cdof);
4169:   PetscSectionGetOffset(section, point, &off);
4170:   a    = &array[off];
4171:   if (!cdof || setBC) {
4172:     if (clperm) {
4173:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4174:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4175:     } else {
4176:       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4177:       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4178:     }
4179:   } else {
4180:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4181:     if (clperm) {
4182:       if (perm) {for (k = 0; k < dof; ++k) {
4183:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4184:           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4185:         }
4186:       } else {
4187:         for (k = 0; k < dof; ++k) {
4188:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4189:           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4190:         }
4191:       }
4192:     } else {
4193:       if (perm) {
4194:         for (k = 0; k < dof; ++k) {
4195:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4196:           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4197:         }
4198:       } else {
4199:         for (k = 0; k < dof; ++k) {
4200:           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4201:           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4202:         }
4203:       }
4204:     }
4205:   }
4206:   return(0);
4207: }

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

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

4260: 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[])
4261: {
4262:   PetscScalar    *a;
4263:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4264:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4265:   PetscInt        cind = 0, b;
4266:   PetscErrorCode  ierr;

4269:   PetscSectionGetFieldDof(section, point, f, &fdof);
4270:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
4271:   PetscSectionGetFieldOffset(section, point, f, &foff);
4272:   a    = &array[foff];
4273:   if (!fcdof || setBC) {
4274:     if (clperm) {
4275:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4276:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4277:     } else {
4278:       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4279:       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4280:     }
4281:   } else {
4282:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4283:     if (clperm) {
4284:       if (perm) {
4285:         for (b = 0; b < fdof; b++) {
4286:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4287:           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4288:         }
4289:       } else {
4290:         for (b = 0; b < fdof; b++) {
4291:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4292:           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4293:         }
4294:       }
4295:     } else {
4296:       if (perm) {
4297:         for (b = 0; b < fdof; b++) {
4298:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4299:           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4300:         }
4301:       } else {
4302:         for (b = 0; b < fdof; b++) {
4303:           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4304:           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4305:         }
4306:       }
4307:     }
4308:   }
4309:   *offset += fdof;
4310:   return(0);
4311: }

4313: 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[])
4314: {
4315:   PetscScalar    *a;
4316:   PetscInt        fdof, foff, fcdof, foffset = *offset;
4317:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4318:   PetscInt        cind = 0, ncind = 0, b;
4319:   PetscBool       ncSet, fcSet;
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) {
4328:     /* We just override fcdof and fcdofs with Ncc and comps */
4329:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4330:     if (clperm) {
4331:       if (perm) {
4332:         if (comps) {
4333:           for (b = 0; b < fdof; b++) {
4334:             ncSet = fcSet = PETSC_FALSE;
4335:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4336:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4337:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4338:           }
4339:         } else {
4340:           for (b = 0; b < fdof; b++) {
4341:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4342:               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4343:               ++cind;
4344:             }
4345:           }
4346:         }
4347:       } else {
4348:         if (comps) {
4349:           for (b = 0; b < fdof; b++) {
4350:             ncSet = fcSet = PETSC_FALSE;
4351:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4352:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4353:             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4354:           }
4355:         } else {
4356:           for (b = 0; b < fdof; b++) {
4357:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4358:               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4359:               ++cind;
4360:             }
4361:           }
4362:         }
4363:       }
4364:     } else {
4365:       if (perm) {
4366:         if (comps) {
4367:           for (b = 0; b < fdof; b++) {
4368:             ncSet = fcSet = PETSC_FALSE;
4369:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4370:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4371:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4372:           }
4373:         } else {
4374:           for (b = 0; b < fdof; b++) {
4375:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4376:               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4377:               ++cind;
4378:             }
4379:           }
4380:         }
4381:       } else {
4382:         if (comps) {
4383:           for (b = 0; b < fdof; b++) {
4384:             ncSet = fcSet = PETSC_FALSE;
4385:             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4386:             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4387:             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4388:           }
4389:         } else {
4390:           for (b = 0; b < fdof; b++) {
4391:             if ((cind < fcdof) && (b == fcdofs[cind])) {
4392:               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4393:               ++cind;
4394:             }
4395:           }
4396:         }
4397:       }
4398:     }
4399:   }
4400:   *offset += fdof;
4401:   return(0);
4402: }

4404: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4405: {
4406:   PetscScalar    *array;
4407:   const PetscInt *cone, *coneO;
4408:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4409:   PetscErrorCode  ierr;

4412:   PetscSectionGetChart(section, &pStart, &pEnd);
4413:   DMPlexGetConeSize(dm, point, &numPoints);
4414:   DMPlexGetCone(dm, point, &cone);
4415:   DMPlexGetConeOrientation(dm, point, &coneO);
4416:   VecGetArray(v, &array);
4417:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4418:     const PetscInt cp = !p ? point : cone[p-1];
4419:     const PetscInt o  = !p ? 0     : coneO[p-1];

4421:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4422:     PetscSectionGetDof(section, cp, &dof);
4423:     /* ADD_VALUES */
4424:     {
4425:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4426:       PetscScalar    *a;
4427:       PetscInt        cdof, coff, cind = 0, k;

4429:       PetscSectionGetConstraintDof(section, cp, &cdof);
4430:       PetscSectionGetOffset(section, cp, &coff);
4431:       a    = &array[coff];
4432:       if (!cdof) {
4433:         if (o >= 0) {
4434:           for (k = 0; k < dof; ++k) {
4435:             a[k] += values[off+k];
4436:           }
4437:         } else {
4438:           for (k = 0; k < dof; ++k) {
4439:             a[k] += values[off+dof-k-1];
4440:           }
4441:         }
4442:       } else {
4443:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
4444:         if (o >= 0) {
4445:           for (k = 0; k < dof; ++k) {
4446:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4447:             a[k] += values[off+k];
4448:           }
4449:         } else {
4450:           for (k = 0; k < dof; ++k) {
4451:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4452:             a[k] += values[off+dof-k-1];
4453:           }
4454:         }
4455:       }
4456:     }
4457:   }
4458:   VecRestoreArray(v, &array);
4459:   return(0);
4460: }

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

4465:   Not collective

4467:   Input Parameters:
4468: + dm - The DM
4469: . section - The section describing the layout in v, or NULL to use the default section
4470: . v - The local vector
4471: . point - The point in the DM
4472: . values - The array of values
4473: - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4474:          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.

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

4479:   Level: intermediate

4481: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4482: @*/
4483: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4484: {
4485:   PetscSection    clSection;
4486:   IS              clPoints;
4487:   PetscScalar    *array;
4488:   PetscInt       *points = NULL;
4489:   const PetscInt *clp, *clperm;
4490:   PetscInt        depth, numFields, numPoints, p;
4491:   PetscErrorCode  ierr;

4495:   if (!section) {DMGetDefaultSection(dm, &section);}
4498:   DMPlexGetDepth(dm, &depth);
4499:   PetscSectionGetNumFields(section, &numFields);
4500:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4501:     DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);
4502:     return(0);
4503:   }
4504:   /* Get points */
4505:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4506:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4507:   /* Get array */
4508:   VecGetArray(v, &array);
4509:   /* Get values */
4510:   if (numFields > 0) {
4511:     PetscInt offset = 0, f;
4512:     for (f = 0; f < numFields; ++f) {
4513:       const PetscInt    **perms = NULL;
4514:       const PetscScalar **flips = NULL;

4516:       PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4517:       switch (mode) {
4518:       case INSERT_VALUES:
4519:         for (p = 0; p < numPoints; p++) {
4520:           const PetscInt    point = points[2*p];
4521:           const PetscInt    *perm = perms ? perms[p] : NULL;
4522:           const PetscScalar *flip = flips ? flips[p] : NULL;
4523:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4524:         } break;
4525:       case INSERT_ALL_VALUES:
4526:         for (p = 0; p < numPoints; p++) {
4527:           const PetscInt    point = points[2*p];
4528:           const PetscInt    *perm = perms ? perms[p] : NULL;
4529:           const PetscScalar *flip = flips ? flips[p] : NULL;
4530:           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4531:         } break;
4532:       case INSERT_BC_VALUES:
4533:         for (p = 0; p < numPoints; p++) {
4534:           const PetscInt    point = points[2*p];
4535:           const PetscInt    *perm = perms ? perms[p] : NULL;
4536:           const PetscScalar *flip = flips ? flips[p] : NULL;
4537:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4538:         } break;
4539:       case ADD_VALUES:
4540:         for (p = 0; p < numPoints; p++) {
4541:           const PetscInt    point = points[2*p];
4542:           const PetscInt    *perm = perms ? perms[p] : NULL;
4543:           const PetscScalar *flip = flips ? flips[p] : NULL;
4544:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4545:         } break;
4546:       case ADD_ALL_VALUES:
4547:         for (p = 0; p < numPoints; p++) {
4548:           const PetscInt    point = points[2*p];
4549:           const PetscInt    *perm = perms ? perms[p] : NULL;
4550:           const PetscScalar *flip = flips ? flips[p] : NULL;
4551:           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4552:         } break;
4553:       case ADD_BC_VALUES:
4554:         for (p = 0; p < numPoints; p++) {
4555:           const PetscInt    point = points[2*p];
4556:           const PetscInt    *perm = perms ? perms[p] : NULL;
4557:           const PetscScalar *flip = flips ? flips[p] : NULL;
4558:           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4559:         } break;
4560:       default:
4561:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4562:       }
4563:       PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4564:     }
4565:   } else {
4566:     PetscInt dof, off;
4567:     const PetscInt    **perms = NULL;
4568:     const PetscScalar **flips = NULL;

4570:     PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);
4571:     switch (mode) {
4572:     case INSERT_VALUES:
4573:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4574:         const PetscInt    point = points[2*p];
4575:         const PetscInt    *perm = perms ? perms[p] : NULL;
4576:         const PetscScalar *flip = flips ? flips[p] : NULL;
4577:         PetscSectionGetDof(section, point, &dof);
4578:         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4579:       } break;
4580:     case INSERT_ALL_VALUES:
4581:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4582:         const PetscInt    point = points[2*p];
4583:         const PetscInt    *perm = perms ? perms[p] : NULL;
4584:         const PetscScalar *flip = flips ? flips[p] : NULL;
4585:         PetscSectionGetDof(section, point, &dof);
4586:         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4587:       } break;
4588:     case INSERT_BC_VALUES:
4589:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4590:         const PetscInt    point = points[2*p];
4591:         const PetscInt    *perm = perms ? perms[p] : NULL;
4592:         const PetscScalar *flip = flips ? flips[p] : NULL;
4593:         PetscSectionGetDof(section, point, &dof);
4594:         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4595:       } break;
4596:     case ADD_VALUES:
4597:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4598:         const PetscInt    point = points[2*p];
4599:         const PetscInt    *perm = perms ? perms[p] : NULL;
4600:         const PetscScalar *flip = flips ? flips[p] : NULL;
4601:         PetscSectionGetDof(section, point, &dof);
4602:         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4603:       } break;
4604:     case ADD_ALL_VALUES:
4605:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4606:         const PetscInt    point = points[2*p];
4607:         const PetscInt    *perm = perms ? perms[p] : NULL;
4608:         const PetscScalar *flip = flips ? flips[p] : NULL;
4609:         PetscSectionGetDof(section, point, &dof);
4610:         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4611:       } break;
4612:     case ADD_BC_VALUES:
4613:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4614:         const PetscInt    point = points[2*p];
4615:         const PetscInt    *perm = perms ? perms[p] : NULL;
4616:         const PetscScalar *flip = flips ? flips[p] : NULL;
4617:         PetscSectionGetDof(section, point, &dof);
4618:         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4619:       } break;
4620:     default:
4621:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4622:     }
4623:     PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);
4624:   }
4625:   /* Cleanup points */
4626:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4627:   /* Cleanup array */
4628:   VecRestoreArray(v, &array);
4629:   return(0);
4630: }

4632: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4633: {
4634:   PetscSection      clSection;
4635:   IS                clPoints;
4636:   PetscScalar       *array;
4637:   PetscInt          *points = NULL;
4638:   const PetscInt    *clp, *clperm;
4639:   PetscInt          numFields, numPoints, p;
4640:   PetscInt          offset = 0, f;
4641:   PetscErrorCode    ierr;

4645:   if (!section) {DMGetDefaultSection(dm, &section);}
4648:   PetscSectionGetNumFields(section, &numFields);
4649:   /* Get points */
4650:   PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);
4651:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4652:   /* Get array */
4653:   VecGetArray(v, &array);
4654:   /* Get values */
4655:   for (f = 0; f < numFields; ++f) {
4656:     const PetscInt    **perms = NULL;
4657:     const PetscScalar **flips = NULL;

4659:     if (!fieldActive[f]) {
4660:       for (p = 0; p < numPoints*2; p += 2) {
4661:         PetscInt fdof;
4662:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
4663:         offset += fdof;
4664:       }
4665:       continue;
4666:     }
4667:     PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4668:     switch (mode) {
4669:     case INSERT_VALUES:
4670:       for (p = 0; p < numPoints; p++) {
4671:         const PetscInt    point = points[2*p];
4672:         const PetscInt    *perm = perms ? perms[p] : NULL;
4673:         const PetscScalar *flip = flips ? flips[p] : NULL;
4674:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4675:       } break;
4676:     case INSERT_ALL_VALUES:
4677:       for (p = 0; p < numPoints; p++) {
4678:         const PetscInt    point = points[2*p];
4679:         const PetscInt    *perm = perms ? perms[p] : NULL;
4680:         const PetscScalar *flip = flips ? flips[p] : NULL;
4681:         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4682:         } break;
4683:     case INSERT_BC_VALUES:
4684:       for (p = 0; p < numPoints; p++) {
4685:         const PetscInt    point = points[2*p];
4686:         const PetscInt    *perm = perms ? perms[p] : NULL;
4687:         const PetscScalar *flip = flips ? flips[p] : NULL;
4688:         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4689:       } break;
4690:     case ADD_VALUES:
4691:       for (p = 0; p < numPoints; p++) {
4692:         const PetscInt    point = points[2*p];
4693:         const PetscInt    *perm = perms ? perms[p] : NULL;
4694:         const PetscScalar *flip = flips ? flips[p] : NULL;
4695:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4696:       } break;
4697:     case ADD_ALL_VALUES:
4698:       for (p = 0; p < numPoints; p++) {
4699:         const PetscInt    point = points[2*p];
4700:         const PetscInt    *perm = perms ? perms[p] : NULL;
4701:         const PetscScalar *flip = flips ? flips[p] : NULL;
4702:         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4703:       } break;
4704:     default:
4705:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4706:     }
4707:     PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);
4708:   }
4709:   /* Cleanup points */
4710:   DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
4711:   /* Cleanup array */
4712:   VecRestoreArray(v, &array);
4713:   return(0);
4714: }

4716: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4717: {
4718:   PetscMPIInt    rank;
4719:   PetscInt       i, j;

4723:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
4724:   PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);
4725:   for (i = 0; i < numRIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);}
4726:   for (i = 0; i < numCIndices; i++) {PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);}
4727:   numCIndices = numCIndices ? numCIndices : numRIndices;
4728:   for (i = 0; i < numRIndices; i++) {
4729:     PetscViewerASCIIPrintf(viewer, "[%d]", rank);
4730:     for (j = 0; j < numCIndices; j++) {
4731: #if defined(PETSC_USE_COMPLEX)
4732:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));
4733: #else
4734:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);
4735: #endif
4736:     }
4737:     PetscViewerASCIIPrintf(viewer, "\n");
4738:   }
4739:   return(0);
4740: }

4742: /* . off - The global offset of this point */
4743: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], PetscInt indices[])
4744: {
4745:   PetscInt        dof;    /* The number of unknowns on this point */
4746:   PetscInt        cdof;   /* The number of constraints on this point */
4747:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4748:   PetscInt        cind = 0, k;
4749:   PetscErrorCode  ierr;

4752:   PetscSectionGetDof(section, point, &dof);
4753:   PetscSectionGetConstraintDof(section, point, &cdof);
4754:   if (!cdof || setBC) {
4755:     if (perm) {
4756:       for (k = 0; k < dof; k++) indices[*loff+perm[k]] = off + k;
4757:     } else {
4758:       for (k = 0; k < dof; k++) indices[*loff+k] = off + k;
4759:     }
4760:   } else {
4761:     PetscSectionGetConstraintIndices(section, point, &cdofs);
4762:     if (perm) {
4763:       for (k = 0; k < dof; ++k) {
4764:         if ((cind < cdof) && (k == cdofs[cind])) {
4765:           /* Insert check for returning constrained indices */
4766:           indices[*loff+perm[k]] = -(off+k+1);
4767:           ++cind;
4768:         } else {
4769:           indices[*loff+perm[k]] = off+k-cind;
4770:         }
4771:       }
4772:     } else {
4773:       for (k = 0; k < dof; ++k) {
4774:         if ((cind < cdof) && (k == cdofs[cind])) {
4775:           /* Insert check for returning constrained indices */
4776:           indices[*loff+k] = -(off+k+1);
4777:           ++cind;
4778:         } else {
4779:           indices[*loff+k] = off+k-cind;
4780:         }
4781:       }
4782:     }
4783:   }
4784:   *loff += dof;
4785:   return(0);
4786: }

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

4795:   PetscSectionGetNumFields(section, &numFields);
4796:   for (f = 0, foff = 0; f < numFields; ++f) {
4797:     PetscInt        fdof, cfdof;
4798:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4799:     PetscInt        cind = 0, b;
4800:     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

4802:     PetscSectionGetFieldDof(section, point, f, &fdof);
4803:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
4804:     if (!cfdof || setBC) {
4805:       if (perm) {for (b = 0; b < fdof; b++) {indices[foffs[f]+perm[b]] = off+foff+b;}}
4806:       else      {for (b = 0; b < fdof; b++) {indices[foffs[f]+     b ] = off+foff+b;}}
4807:     } else {
4808:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
4809:       if (perm) {
4810:         for (b = 0; b < fdof; b++) {
4811:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4812:             indices[foffs[f]+perm[b]] = -(off+foff+b+1);
4813:             ++cind;
4814:           } else {
4815:             indices[foffs[f]+perm[b]] = off+foff+b-cind;
4816:           }
4817:         }
4818:       } else {
4819:         for (b = 0; b < fdof; b++) {
4820:           if ((cind < cfdof) && (b == fcdofs[cind])) {
4821:             indices[foffs[f]+b] = -(off+foff+b+1);
4822:             ++cind;
4823:           } else {
4824:             indices[foffs[f]+b] = off+foff+b-cind;
4825:           }
4826:         }
4827:       }
4828:     }
4829:     foff     += (setBC ? fdof : (fdof - cfdof));
4830:     foffs[f] += fdof;
4831:   }
4832:   return(0);
4833: }

4835: 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)
4836: {
4837:   Mat             cMat;
4838:   PetscSection    aSec, cSec;
4839:   IS              aIS;
4840:   PetscInt        aStart = -1, aEnd = -1;
4841:   const PetscInt  *anchors;
4842:   PetscInt        numFields, f, p, q, newP = 0;
4843:   PetscInt        newNumPoints = 0, newNumIndices = 0;
4844:   PetscInt        *newPoints, *indices, *newIndices;
4845:   PetscInt        maxAnchor, maxDof;
4846:   PetscInt        newOffsets[32];
4847:   PetscInt        *pointMatOffsets[32];
4848:   PetscInt        *newPointOffsets[32];
4849:   PetscScalar     *pointMat[32];
4850:   PetscScalar     *newValues=NULL,*tmpValues;
4851:   PetscBool       anyConstrained = PETSC_FALSE;
4852:   PetscErrorCode  ierr;

4857:   PetscSectionGetNumFields(section, &numFields);

4859:   DMPlexGetAnchors(dm,&aSec,&aIS);
4860:   /* if there are point-to-point constraints */
4861:   if (aSec) {
4862:     PetscMemzero(newOffsets, 32 * sizeof(PetscInt));
4863:     ISGetIndices(aIS,&anchors);
4864:     PetscSectionGetChart(aSec,&aStart,&aEnd);
4865:     /* figure out how many points are going to be in the new element matrix
4866:      * (we allow double counting, because it's all just going to be summed
4867:      * into the global matrix anyway) */
4868:     for (p = 0; p < 2*numPoints; p+=2) {
4869:       PetscInt b    = points[p];
4870:       PetscInt bDof = 0, bSecDof;

4872:       PetscSectionGetDof(section,b,&bSecDof);
4873:       if (!bSecDof) {
4874:         continue;
4875:       }
4876:       if (b >= aStart && b < aEnd) {
4877:         PetscSectionGetDof(aSec,b,&bDof);
4878:       }
4879:       if (bDof) {
4880:         /* this point is constrained */
4881:         /* it is going to be replaced by its anchors */
4882:         PetscInt bOff, q;

4884:         anyConstrained = PETSC_TRUE;
4885:         newNumPoints  += bDof;
4886:         PetscSectionGetOffset(aSec,b,&bOff);
4887:         for (q = 0; q < bDof; q++) {
4888:           PetscInt a = anchors[bOff + q];
4889:           PetscInt aDof;

4891:           PetscSectionGetDof(section,a,&aDof);
4892:           newNumIndices += aDof;
4893:           for (f = 0; f < numFields; ++f) {
4894:             PetscInt fDof;

4896:             PetscSectionGetFieldDof(section, a, f, &fDof);
4897:             newOffsets[f+1] += fDof;
4898:           }
4899:         }
4900:       }
4901:       else {
4902:         /* this point is not constrained */
4903:         newNumPoints++;
4904:         newNumIndices += bSecDof;
4905:         for (f = 0; f < numFields; ++f) {
4906:           PetscInt fDof;

4908:           PetscSectionGetFieldDof(section, b, f, &fDof);
4909:           newOffsets[f+1] += fDof;
4910:         }
4911:       }
4912:     }
4913:   }
4914:   if (!anyConstrained) {
4915:     if (outNumPoints)  *outNumPoints  = 0;
4916:     if (outNumIndices) *outNumIndices = 0;
4917:     if (outPoints)     *outPoints     = NULL;
4918:     if (outValues)     *outValues     = NULL;
4919:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4920:     return(0);
4921:   }

4923:   if (outNumPoints)  *outNumPoints  = newNumPoints;
4924:   if (outNumIndices) *outNumIndices = newNumIndices;

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

4928:   if (!outPoints && !outValues) {
4929:     if (offsets) {
4930:       for (f = 0; f <= numFields; f++) {
4931:         offsets[f] = newOffsets[f];
4932:       }
4933:     }
4934:     if (aSec) {ISRestoreIndices(aIS,&anchors);}
4935:     return(0);
4936:   }

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

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

4942:   /* workspaces */
4943:   if (numFields) {
4944:     for (f = 0; f < numFields; f++) {
4945:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
4946:       DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
4947:     }
4948:   }
4949:   else {
4950:     DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
4951:     DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);
4952:   }

4954:   /* get workspaces for the point-to-point matrices */
4955:   if (numFields) {
4956:     PetscInt totalOffset, totalMatOffset;

4958:     for (p = 0; p < numPoints; p++) {
4959:       PetscInt b    = points[2*p];
4960:       PetscInt bDof = 0, bSecDof;

4962:       PetscSectionGetDof(section,b,&bSecDof);
4963:       if (!bSecDof) {
4964:         for (f = 0; f < numFields; f++) {
4965:           newPointOffsets[f][p + 1] = 0;
4966:           pointMatOffsets[f][p + 1] = 0;
4967:         }
4968:         continue;
4969:       }
4970:       if (b >= aStart && b < aEnd) {
4971:         PetscSectionGetDof(aSec, b, &bDof);
4972:       }
4973:       if (bDof) {
4974:         for (f = 0; f < numFields; f++) {
4975:           PetscInt fDof, q, bOff, allFDof = 0;

4977:           PetscSectionGetFieldDof(section, b, f, &fDof);
4978:           PetscSectionGetOffset(aSec, b, &bOff);
4979:           for (q = 0; q < bDof; q++) {
4980:             PetscInt a = anchors[bOff + q];
4981:             PetscInt aFDof;

4983:             PetscSectionGetFieldDof(section, a, f, &aFDof);
4984:             allFDof += aFDof;
4985:           }
4986:           newPointOffsets[f][p+1] = allFDof;
4987:           pointMatOffsets[f][p+1] = fDof * allFDof;
4988:         }
4989:       }
4990:       else {
4991:         for (f = 0; f < numFields; f++) {
4992:           PetscInt fDof;

4994:           PetscSectionGetFieldDof(section, b, f, &fDof);
4995:           newPointOffsets[f][p+1] = fDof;
4996:           pointMatOffsets[f][p+1] = 0;
4997:         }
4998:       }
4999:     }
5000:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5001:       newPointOffsets[f][0] = totalOffset;
5002:       pointMatOffsets[f][0] = totalMatOffset;
5003:       for (p = 0; p < numPoints; p++) {
5004:         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5005:         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5006:       }
5007:       totalOffset    = newPointOffsets[f][numPoints];
5008:       totalMatOffset = pointMatOffsets[f][numPoints];
5009:       DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5010:     }
5011:   }
5012:   else {
5013:     for (p = 0; p < numPoints; p++) {
5014:       PetscInt b    = points[2*p];
5015:       PetscInt bDof = 0, bSecDof;

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

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

5033:           PetscSectionGetDof(section, a, &aDof);
5034:           allDof += aDof;
5035:         }
5036:         newPointOffsets[0][p+1] = allDof;
5037:         pointMatOffsets[0][p+1] = bSecDof * allDof;
5038:       }
5039:       else {
5040:         newPointOffsets[0][p+1] = bSecDof;
5041:         pointMatOffsets[0][p+1] = 0;
5042:       }
5043:     }
5044:     newPointOffsets[0][0] = 0;
5045:     pointMatOffsets[0][0] = 0;
5046:     for (p = 0; p < numPoints; p++) {
5047:       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5048:       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5049:     }
5050:     DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5051:   }

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

5056:   /* get the point-to-point matrices; construct newPoints */
5057:   PetscSectionGetMaxDof(aSec, &maxAnchor);
5058:   PetscSectionGetMaxDof(section, &maxDof);
5059:   DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);
5060:   DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);
5061:   if (numFields) {
5062:     for (p = 0, newP = 0; p < numPoints; p++) {
5063:       PetscInt b    = points[2*p];
5064:       PetscInt o    = points[2*p+1];
5065:       PetscInt bDof = 0, bSecDof;

5067:       PetscSectionGetDof(section, b, &bSecDof);
5068:       if (!bSecDof) {
5069:         continue;
5070:       }
5071:       if (b >= aStart && b < aEnd) {
5072:         PetscSectionGetDof(aSec, b, &bDof);
5073:       }
5074:       if (bDof) {
5075:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

5077:         fStart[0] = 0;
5078:         fEnd[0]   = 0;
5079:         for (f = 0; f < numFields; f++) {
5080:           PetscInt fDof;

5082:           PetscSectionGetFieldDof(cSec, b, f, &fDof);
5083:           fStart[f+1] = fStart[f] + fDof;
5084:           fEnd[f+1]   = fStart[f+1];
5085:         }
5086:         PetscSectionGetOffset(cSec, b, &bOff);
5087:         DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, indices);

5089:         fAnchorStart[0] = 0;
5090:         fAnchorEnd[0]   = 0;
5091:         for (f = 0; f < numFields; f++) {
5092:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

5094:           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5095:           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5096:         }
5097:         PetscSectionGetOffset(aSec, b, &bOff);
5098:         for (q = 0; q < bDof; q++) {
5099:           PetscInt a = anchors[bOff + q], aOff;

5101:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5102:           newPoints[2*(newP + q)]     = a;
5103:           newPoints[2*(newP + q) + 1] = 0;
5104:           PetscSectionGetOffset(section, a, &aOff);
5105:           DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, newIndices);
5106:         }
5107:         newP += bDof;

5109:         if (outValues) {
5110:           /* get the point-to-point submatrix */
5111:           for (f = 0; f < numFields; f++) {
5112:             MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);
5113:           }
5114:         }
5115:       }
5116:       else {
5117:         newPoints[2 * newP]     = b;
5118:         newPoints[2 * newP + 1] = o;
5119:         newP++;
5120:       }
5121:     }
5122:   } else {
5123:     for (p = 0; p < numPoints; p++) {
5124:       PetscInt b    = points[2*p];
5125:       PetscInt o    = points[2*p+1];
5126:       PetscInt bDof = 0, bSecDof;

5128:       PetscSectionGetDof(section, b, &bSecDof);
5129:       if (!bSecDof) {
5130:         continue;
5131:       }
5132:       if (b >= aStart && b < aEnd) {
5133:         PetscSectionGetDof(aSec, b, &bDof);
5134:       }
5135:       if (bDof) {
5136:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

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

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

5147:           newPoints[2*(newP + q)]     = a;
5148:           newPoints[2*(newP + q) + 1] = 0;
5149:           PetscSectionGetOffset(section, a, &aOff);
5150:           DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, newIndices);
5151:         }
5152:         newP += bDof;

5154:         /* get the point-to-point submatrix */
5155:         if (outValues) {
5156:           MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);
5157:         }
5158:       }
5159:       else {
5160:         newPoints[2 * newP]     = b;
5161:         newPoints[2 * newP + 1] = o;
5162:         newP++;
5163:       }
5164:     }
5165:   }

5167:   if (outValues) {
5168:     DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5169:     PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));
5170:     /* multiply constraints on the right */
5171:     if (numFields) {
5172:       for (f = 0; f < numFields; f++) {
5173:         PetscInt oldOff = offsets[f];

5175:         for (p = 0; p < numPoints; p++) {
5176:           PetscInt cStart = newPointOffsets[f][p];
5177:           PetscInt b      = points[2 * p];
5178:           PetscInt c, r, k;
5179:           PetscInt dof;

5181:           PetscSectionGetFieldDof(section,b,f,&dof);
5182:           if (!dof) {
5183:             continue;
5184:           }
5185:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5186:             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5187:             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];

5189:             for (r = 0; r < numIndices; r++) {
5190:               for (c = 0; c < nCols; c++) {
5191:                 for (k = 0; k < dof; k++) {
5192:                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5193:                 }
5194:               }
5195:             }
5196:           }
5197:           else {
5198:             /* copy this column as is */
5199:             for (r = 0; r < numIndices; r++) {
5200:               for (c = 0; c < dof; c++) {
5201:                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5202:               }
5203:             }
5204:           }
5205:           oldOff += dof;
5206:         }
5207:       }
5208:     }
5209:     else {
5210:       PetscInt oldOff = 0;
5211:       for (p = 0; p < numPoints; p++) {
5212:         PetscInt cStart = newPointOffsets[0][p];
5213:         PetscInt b      = points[2 * p];
5214:         PetscInt c, r, k;
5215:         PetscInt dof;

5217:         PetscSectionGetDof(section,b,&dof);
5218:         if (!dof) {
5219:           continue;
5220:         }
5221:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5222:           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5223:           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];

5225:           for (r = 0; r < numIndices; r++) {
5226:             for (c = 0; c < nCols; c++) {
5227:               for (k = 0; k < dof; k++) {
5228:                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5229:               }
5230:             }
5231:           }
5232:         }
5233:         else {
5234:           /* copy this column as is */
5235:           for (r = 0; r < numIndices; r++) {
5236:             for (c = 0; c < dof; c++) {
5237:               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5238:             }
5239:           }
5240:         }
5241:         oldOff += dof;
5242:       }
5243:     }

5245:     if (multiplyLeft) {
5246:       DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5247:       PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));
5248:       /* multiply constraints transpose on the left */
5249:       if (numFields) {
5250:         for (f = 0; f < numFields; f++) {
5251:           PetscInt oldOff = offsets[f];

5253:           for (p = 0; p < numPoints; p++) {
5254:             PetscInt rStart = newPointOffsets[f][p];
5255:             PetscInt b      = points[2 * p];
5256:             PetscInt c, r, k;
5257:             PetscInt dof;

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

5264:               for (r = 0; r < nRows; r++) {
5265:                 for (c = 0; c < newNumIndices; c++) {
5266:                   for (k = 0; k < dof; k++) {
5267:                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5268:                   }
5269:                 }
5270:               }
5271:             }
5272:             else {
5273:               /* copy this row as is */
5274:               for (r = 0; r < dof; r++) {
5275:                 for (c = 0; c < newNumIndices; c++) {
5276:                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5277:                 }
5278:               }
5279:             }
5280:             oldOff += dof;
5281:           }
5282:         }
5283:       }
5284:       else {
5285:         PetscInt oldOff = 0;

5287:         for (p = 0; p < numPoints; p++) {
5288:           PetscInt rStart = newPointOffsets[0][p];
5289:           PetscInt b      = points[2 * p];
5290:           PetscInt c, r, k;
5291:           PetscInt dof;

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

5298:             for (r = 0; r < nRows; r++) {
5299:               for (c = 0; c < newNumIndices; c++) {
5300:                 for (k = 0; k < dof; k++) {
5301:                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5302:                 }
5303:               }
5304:             }
5305:           }
5306:           else {
5307:             /* copy this row as is */
5308:             for (r = 0; r < dof; r++) {
5309:               for (c = 0; c < newNumIndices; c++) {
5310:                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5311:               }
5312:             }
5313:           }
5314:           oldOff += dof;
5315:         }
5316:       }

5318:       DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);
5319:     }
5320:     else {
5321:       newValues = tmpValues;
5322:     }
5323:   }

5325:   /* clean up */
5326:   DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);
5327:   DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);

5329:   if (numFields) {
5330:     for (f = 0; f < numFields; f++) {
5331:       DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);
5332:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);
5333:       DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);
5334:     }
5335:   }
5336:   else {
5337:     DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);
5338:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);
5339:     DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);
5340:   }
5341:   ISRestoreIndices(aIS,&anchors);

5343:   /* output */
5344:   if (outPoints) {
5345:     *outPoints = newPoints;
5346:   }
5347:   else {
5348:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5349:   }
5350:   if (outValues) {
5351:     *outValues = newValues;
5352:   }
5353:   for (f = 0; f <= numFields; f++) {
5354:     offsets[f] = newOffsets[f];
5355:   }
5356:   return(0);
5357: }

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

5362:   Not collective

5364:   Input Parameters:
5365: + dm - The DM
5366: . section - The section describing the layout in v, or NULL to use the default section
5367: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5368: - point - The mesh point

5370:   Output parameters:
5371: + numIndices - The number of indices
5372: . indices - The indices
5373: - outOffsets - Field offset if not NULL

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

5377:   Level: advanced

5379: .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5380: @*/
5381: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5382: {
5383:   PetscSection    clSection;
5384:   IS              clPoints;
5385:   const PetscInt *clp;
5386:   const PetscInt  **perms[32] = {NULL};
5387:   PetscInt       *points = NULL, *pointsNew;
5388:   PetscInt        numPoints, numPointsNew;
5389:   PetscInt        offsets[32];
5390:   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5391:   PetscErrorCode  ierr;

5399:   PetscSectionGetNumFields(section, &Nf);
5400:   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5401:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5402:   /* Get points in closure */
5403:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5404:   /* Get number of indices and indices per field */
5405:   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5406:     PetscInt dof, fdof;

5408:     PetscSectionGetDof(section, points[p], &dof);
5409:     for (f = 0; f < Nf; ++f) {
5410:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5411:       offsets[f+1] += fdof;
5412:     }
5413:     Nind += dof;
5414:   }
5415:   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5416:   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5417:   if (!Nf) offsets[1] = Nind;
5418:   /* Get dual space symmetries */
5419:   for (f = 0; f < PetscMax(1,Nf); f++) {
5420:     if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5421:     else    {PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);}
5422:   }
5423:   /* Correct for hanging node constraints */
5424:   {
5425:     DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);
5426:     if (numPointsNew) {
5427:       for (f = 0; f < PetscMax(1,Nf); f++) {
5428:         if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5429:         else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5430:       }
5431:       for (f = 0; f < PetscMax(1,Nf); f++) {
5432:         if (Nf) {PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);}
5433:         else    {PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);}
5434:       }
5435:       DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5436:       numPoints = numPointsNew;
5437:       Nind      = NindNew;
5438:       points    = pointsNew;
5439:     }
5440:   }
5441:   /* Calculate indices */
5442:   DMGetWorkArray(dm, Nind, MPIU_INT, indices);
5443:   if (Nf) {
5444:     if (outOffsets) {
5445:       PetscInt f;

5447:       for (f = 0; f <= Nf; f++) {
5448:         outOffsets[f] = offsets[f];
5449:       }
5450:     }
5451:     for (p = 0; p < numPoints; p++) {
5452:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5453:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, *indices);
5454:     }
5455:   } else {
5456:     for (p = 0, off = 0; p < numPoints; p++) {
5457:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

5459:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5460:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, *indices);
5461:     }
5462:   }
5463:   /* Cleanup points */
5464:   for (f = 0; f < PetscMax(1,Nf); f++) {
5465:     if (Nf) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);}
5466:     else    {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);}
5467:   }
5468:   if (numPointsNew) {
5469:     DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);
5470:   } else {
5471:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5472:   }
5473:   if (numIndices) *numIndices = Nind;
5474:   return(0);
5475: }

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

5480:   Not collective

5482:   Input Parameters:
5483: + dm - The DM
5484: . section - The section describing the layout in v, or NULL to use the default section
5485: . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5486: . point - The mesh point
5487: . numIndices - The number of indices
5488: . indices - The indices
5489: - outOffsets - Field offset if not NULL

5491:   Level: advanced

5493: .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5494: @*/
5495: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5496: {

5502:   DMRestoreWorkArray(dm, 0, MPIU_INT, indices);
5503:   return(0);
5504: }

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

5509:   Not collective

5511:   Input Parameters:
5512: + dm - The DM
5513: . section - The section describing the layout in v, or NULL to use the default section
5514: . globalSection - The section describing the layout in v, or NULL to use the default global section
5515: . A - The matrix
5516: . point - The point in the DM
5517: . values - The array of values
5518: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

5523:   Level: intermediate

5525: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5526: @*/
5527: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5528: {
5529:   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5530:   PetscSection        clSection;
5531:   IS                  clPoints;
5532:   PetscInt           *points = NULL, *newPoints;
5533:   const PetscInt     *clp;
5534:   PetscInt           *indices;
5535:   PetscInt            offsets[32];
5536:   const PetscInt    **perms[32] = {NULL};
5537:   const PetscScalar **flips[32] = {NULL};
5538:   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5539:   PetscScalar        *valCopy = NULL;
5540:   PetscScalar        *newValues;
5541:   PetscErrorCode      ierr;

5545:   if (!section) {DMGetDefaultSection(dm, &section);}
5547:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5550:   PetscSectionGetNumFields(section, &numFields);
5551:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5552:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5553:   DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5554:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5555:     PetscInt fdof;

5557:     PetscSectionGetDof(section, points[p], &dof);
5558:     for (f = 0; f < numFields; ++f) {
5559:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5560:       offsets[f+1] += fdof;
5561:     }
5562:     numIndices += dof;
5563:   }
5564:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

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

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

5578:         if (!numFields) {
5579:           PetscSectionGetDof(section,point,&fdof);
5580:         } else {
5581:           PetscSectionGetFieldDof(section,point,f,&fdof);
5582:         }
5583:         if (flip) {
5584:           PetscInt i, j, k;

5586:           if (!valCopy) {
5587:             DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5588:             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5589:             values = valCopy;
5590:           }
5591:           for (i = 0; i < fdof; i++) {
5592:             PetscScalar fval = flip[i];

5594:             for (k = 0; k < numIndices; k++) {
5595:               valCopy[numIndices * (foffset + i) + k] *= fval;
5596:               valCopy[numIndices * k + (foffset + i)] *= fval;
5597:             }
5598:           }
5599:         }
5600:         foffset += fdof;
5601:       }
5602:     }
5603:   }
5604:   DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);
5605:   if (newNumPoints) {
5606:     if (valCopy) {
5607:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5608:     }
5609:     for (f = 0; f < PetscMax(1,numFields); f++) {
5610:       if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5611:       else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5612:     }
5613:     for (f = 0; f < PetscMax(1,numFields); f++) {
5614:       if (numFields) {PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);}
5615:       else           {PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);}
5616:     }
5617:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5618:     numPoints  = newNumPoints;
5619:     numIndices = newNumIndices;
5620:     points     = newPoints;
5621:     values     = newValues;
5622:   }
5623:   DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);
5624:   if (numFields) {
5625:     for (p = 0; p < numPoints; p++) {
5626:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5627:       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, indices);
5628:     }
5629:   } else {
5630:     for (p = 0, off = 0; p < numPoints; p++) {
5631:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5632:       PetscSectionGetOffset(globalSection, points[2*p], &globalOff);
5633:       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, indices);
5634:     }
5635:   }
5636:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);}
5637:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5638:   if (mesh->printFEM > 1) {
5639:     PetscInt i;
5640:     PetscPrintf(PETSC_COMM_SELF, "  Indices:");
5641:     for (i = 0; i < numIndices; ++i) {PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);}
5642:     PetscPrintf(PETSC_COMM_SELF, "\n");
5643:   }
5644:   if (ierr) {
5645:     PetscMPIInt    rank;
5646:     PetscErrorCode ierr2;

5648:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5649:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5650:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5651:     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5652: 
5653:   }
5654:   for (f = 0; f < PetscMax(1,numFields); f++) {
5655:     if (numFields) {PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);}
5656:     else           {PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);}
5657:   }
5658:   if (newNumPoints) {
5659:     DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);
5660:     DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);
5661:   }
5662:   else {
5663:     if (valCopy) {
5664:       DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);
5665:     }
5666:     DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);
5667:   }
5668:   DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);
5669:   return(0);
5670: }

5672: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5673: {
5674:   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5675:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5676:   PetscInt       *cpoints = NULL;
5677:   PetscInt       *findices, *cindices;
5678:   PetscInt        foffsets[32], coffsets[32];
5679:   CellRefiner     cellRefiner;
5680:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5681:   PetscErrorCode  ierr;

5686:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5688:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5690:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5692:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5695:   PetscSectionGetNumFields(fsection, &numFields);
5696:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5697:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5698:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5699:   /* Column indices */
5700:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5701:   maxFPoints = numCPoints;
5702:   /* Compress out points not in the section */
5703:   /*   TODO: Squeeze out points with 0 dof as well */
5704:   PetscSectionGetChart(csection, &pStart, &pEnd);
5705:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5706:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5707:       cpoints[q*2]   = cpoints[p];
5708:       cpoints[q*2+1] = cpoints[p+1];
5709:       ++q;
5710:     }
5711:   }
5712:   numCPoints = q;
5713:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5714:     PetscInt fdof;

5716:     PetscSectionGetDof(csection, cpoints[p], &dof);
5717:     if (!dof) continue;
5718:     for (f = 0; f < numFields; ++f) {
5719:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5720:       coffsets[f+1] += fdof;
5721:     }
5722:     numCIndices += dof;
5723:   }
5724:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5725:   /* Row indices */
5726:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5727:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5728:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5729:   for (r = 0, q = 0; r < numSubcells; ++r) {
5730:     /* TODO Map from coarse to fine cells */
5731:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5732:     /* Compress out points not in the section */
5733:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5734:     for (p = 0; p < numFPoints*2; p += 2) {
5735:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5736:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5737:         if (!dof) continue;
5738:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5739:         if (s < q) continue;
5740:         ftotpoints[q*2]   = fpoints[p];
5741:         ftotpoints[q*2+1] = fpoints[p+1];
5742:         ++q;
5743:       }
5744:     }
5745:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5746:   }
5747:   numFPoints = q;
5748:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5749:     PetscInt fdof;

5751:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5752:     if (!dof) continue;
5753:     for (f = 0; f < numFields; ++f) {
5754:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5755:       foffsets[f+1] += fdof;
5756:     }
5757:     numFIndices += dof;
5758:   }
5759:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

5761:   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
5762:   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
5763:   DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5764:   DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5765:   if (numFields) {
5766:     const PetscInt **permsF[32] = {NULL};
5767:     const PetscInt **permsC[32] = {NULL};

5769:     for (f = 0; f < numFields; f++) {
5770:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5771:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5772:     }
5773:     for (p = 0; p < numFPoints; p++) {
5774:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5775:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5776:     }
5777:     for (p = 0; p < numCPoints; p++) {
5778:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5779:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5780:     }
5781:     for (f = 0; f < numFields; f++) {
5782:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5783:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5784:     }
5785:   } else {
5786:     const PetscInt **permsF = NULL;
5787:     const PetscInt **permsC = NULL;

5789:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5790:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5791:     for (p = 0, off = 0; p < numFPoints; p++) {
5792:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5794:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5795:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5796:     }
5797:     for (p = 0, off = 0; p < numCPoints; p++) {
5798:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5800:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5801:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5802:     }
5803:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5804:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5805:   }
5806:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);}
5807:   /* TODO: flips */
5808:   MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5809:   if (ierr) {
5810:     PetscMPIInt    rank;
5811:     PetscErrorCode ierr2;

5813:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5814:     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5815:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5816:     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
5817:     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
5818: 
5819:   }
5820:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
5821:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5822:   DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);
5823:   DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);
5824:   return(0);
5825: }

5827: PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5828: {
5829:   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5830:   PetscInt      *cpoints = NULL;
5831:   PetscInt       foffsets[32], coffsets[32];
5832:   CellRefiner    cellRefiner;
5833:   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;

5839:   if (!fsection) {DMGetDefaultSection(dmf, &fsection);}
5841:   if (!csection) {DMGetDefaultSection(dmc, &csection);}
5843:   if (!globalFSection) {DMGetDefaultGlobalSection(dmf, &globalFSection);}
5845:   if (!globalCSection) {DMGetDefaultGlobalSection(dmc, &globalCSection);}
5847:   PetscSectionGetNumFields(fsection, &numFields);
5848:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5849:   PetscMemzero(foffsets, 32 * sizeof(PetscInt));
5850:   PetscMemzero(coffsets, 32 * sizeof(PetscInt));
5851:   /* Column indices */
5852:   DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5853:   maxFPoints = numCPoints;
5854:   /* Compress out points not in the section */
5855:   /*   TODO: Squeeze out points with 0 dof as well */
5856:   PetscSectionGetChart(csection, &pStart, &pEnd);
5857:   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5858:     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5859:       cpoints[q*2]   = cpoints[p];
5860:       cpoints[q*2+1] = cpoints[p+1];
5861:       ++q;
5862:     }
5863:   }
5864:   numCPoints = q;
5865:   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5866:     PetscInt fdof;

5868:     PetscSectionGetDof(csection, cpoints[p], &dof);
5869:     if (!dof) continue;
5870:     for (f = 0; f < numFields; ++f) {
5871:       PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);
5872:       coffsets[f+1] += fdof;
5873:     }
5874:     numCIndices += dof;
5875:   }
5876:   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5877:   /* Row indices */
5878:   DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);
5879:   CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);
5880:   DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);
5881:   for (r = 0, q = 0; r < numSubcells; ++r) {
5882:     /* TODO Map from coarse to fine cells */
5883:     DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);
5884:     /* Compress out points not in the section */
5885:     PetscSectionGetChart(fsection, &pStart, &pEnd);
5886:     for (p = 0; p < numFPoints*2; p += 2) {
5887:       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5888:         PetscSectionGetDof(fsection, fpoints[p], &dof);
5889:         if (!dof) continue;
5890:         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5891:         if (s < q) continue;
5892:         ftotpoints[q*2]   = fpoints[p];
5893:         ftotpoints[q*2+1] = fpoints[p+1];
5894:         ++q;
5895:       }
5896:     }
5897:     DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);
5898:   }
5899:   numFPoints = q;
5900:   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5901:     PetscInt fdof;

5903:     PetscSectionGetDof(fsection, ftotpoints[p], &dof);
5904:     if (!dof) continue;
5905:     for (f = 0; f < numFields; ++f) {
5906:       PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);
5907:       foffsets[f+1] += fdof;
5908:     }
5909:     numFIndices += dof;
5910:   }
5911:   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];

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

5919:     for (f = 0; f < numFields; f++) {
5920:       PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5921:       PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5922:     }
5923:     for (p = 0; p < numFPoints; p++) {
5924:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5925:       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, findices);
5926:     }
5927:     for (p = 0; p < numCPoints; p++) {
5928:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5929:       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cindices);
5930:     }
5931:     for (f = 0; f < numFields; f++) {
5932:       PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);
5933:       PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);
5934:     }
5935:   } else {
5936:     const PetscInt **permsF = NULL;
5937:     const PetscInt **permsC = NULL;

5939:     PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5940:     PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5941:     for (p = 0, off = 0; p < numFPoints; p++) {
5942:       const PetscInt *perm = permsF ? permsF[p] : NULL;

5944:       PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);
5945:       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, findices);
5946:     }
5947:     for (p = 0, off = 0; p < numCPoints; p++) {
5948:       const PetscInt *perm = permsC ? permsC[p] : NULL;

5950:       PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);
5951:       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cindices);
5952:     }
5953:     PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);
5954:     PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);
5955:   }
5956:   DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);
5957:   DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);
5958:   return(0);
5959: }

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

5964:   Input Parameter:
5965: . dm - The DMPlex object

5967:   Output Parameters:
5968: + cMax - The first hybrid cell
5969: . fMax - The first hybrid face
5970: . eMax - The first hybrid edge
5971: - vMax - The first hybrid vertex

5973:   Level: developer

5975: .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5976: @*/
5977: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5978: {
5979:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5980:   PetscInt       dim;

5985:   DMGetDimension(dm, &dim);
5986:   if (cMax) *cMax = mesh->hybridPointMax[dim];
5987:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5988:   if (eMax) *eMax = mesh->hybridPointMax[1];
5989:   if (vMax) *vMax = mesh->hybridPointMax[0];
5990:   return(0);
5991: }

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

5996:   Input Parameters:
5997: . dm   - The DMPlex object
5998: . cMax - The first hybrid cell
5999: . fMax - The first hybrid face
6000: . eMax - The first hybrid edge
6001: - vMax - The first hybrid vertex

6003:   Level: developer

6005: .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6006: @*/
6007: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6008: {
6009:   DM_Plex       *mesh = (DM_Plex*) dm->data;
6010:   PetscInt       dim;

6015:   DMGetDimension(dm, &dim);
6016:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
6017:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
6018:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
6019:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
6020:   return(0);
6021: }

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

6026:   Input Parameter:
6027: . dm   - The DMPlex object

6029:   Output Parameter:
6030: . cellHeight - The height of a cell

6032:   Level: developer

6034: .seealso DMPlexSetVTKCellHeight()
6035: @*/
6036: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6037: {
6038:   DM_Plex *mesh = (DM_Plex*) dm->data;

6043:   *cellHeight = mesh->vtkCellHeight;
6044:   return(0);
6045: }

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

6050:   Input Parameters:
6051: + dm   - The DMPlex object
6052: - cellHeight - The height of a cell

6054:   Level: developer

6056: .seealso DMPlexGetVTKCellHeight()
6057: @*/
6058: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6059: {
6060:   DM_Plex *mesh = (DM_Plex*) dm->data;

6064:   mesh->vtkCellHeight = cellHeight;
6065:   return(0);
6066: }

6068: /* We can easily have a form that takes an IS instead */
6069: static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6070: {
6071:   PetscSection   section, globalSection;
6072:   PetscInt      *numbers, p;

6076:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6077:   PetscSectionSetChart(section, pStart, pEnd);
6078:   for (p = pStart; p < pEnd; ++p) {
6079:     PetscSectionSetDof(section, p, 1);
6080:   }
6081:   PetscSectionSetUp(section);
6082:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);
6083:   PetscMalloc1(pEnd - pStart, &numbers);
6084:   for (p = pStart; p < pEnd; ++p) {
6085:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
6086:     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6087:     else                       numbers[p-pStart] += shift;
6088:   }
6089:   ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
6090:   if (globalSize) {
6091:     PetscLayout layout;
6092:     PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);
6093:     PetscLayoutGetSize(layout, globalSize);
6094:     PetscLayoutDestroy(&layout);
6095:   }
6096:   PetscSectionDestroy(&section);
6097:   PetscSectionDestroy(&globalSection);
6098:   return(0);
6099: }

6101: PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6102: {
6103:   PetscInt       cellHeight, cStart, cEnd, cMax;

6107:   DMPlexGetVTKCellHeight(dm, &cellHeight);
6108:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6109:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6110:   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6111:   DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);
6112:   return(0);
6113: }

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

6118:   Input Parameter:
6119: . dm   - The DMPlex object

6121:   Output Parameter:
6122: . globalCellNumbers - Global cell numbers for all cells on this process

6124:   Level: developer

6126: .seealso DMPlexGetVertexNumbering()
6127: @*/
6128: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6129: {
6130:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6135:   if (!mesh->globalCellNumbers) {DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);}
6136:   *globalCellNumbers = mesh->globalCellNumbers;
6137:   return(0);
6138: }

6140: PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6141: {
6142:   PetscInt       vStart, vEnd, vMax;

6147:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6148:   DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
6149:   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6150:   DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);
6151:   return(0);
6152: }

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

6157:   Input Parameter:
6158: . dm   - The DMPlex object

6160:   Output Parameter:
6161: . globalVertexNumbers - Global vertex numbers for all vertices on this process

6163:   Level: developer

6165: .seealso DMPlexGetCellNumbering()
6166: @*/
6167: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6168: {
6169:   DM_Plex       *mesh = (DM_Plex*) dm->data;

6174:   if (!mesh->globalVertexNumbers) {DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);}
6175:   *globalVertexNumbers = mesh->globalVertexNumbers;
6176:   return(0);
6177: }

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

6182:   Input Parameter:
6183: . dm   - The DMPlex object

6185:   Output Parameter:
6186: . globalPointNumbers - Global numbers for all points on this process

6188:   Level: developer

6190: .seealso DMPlexGetCellNumbering()
6191: @*/
6192: PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6193: {
6194:   IS             nums[4];
6195:   PetscInt       depths[4];
6196:   PetscInt       depth, d, shift = 0;

6201:   DMPlexGetDepth(dm, &depth);
6202:   /* For unstratified meshes use dim instead of depth */
6203:   if (depth < 0) {DMGetDimension(dm, &depth);}
6204:   depths[0] = depth; depths[1] = 0;
6205:   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
6206:   for (d = 0; d <= depth; ++d) {
6207:     PetscInt pStart, pEnd, gsize;

6209:     DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);
6210:     DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);
6211:     shift += gsize;
6212:   }
6213:   ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
6214:   for (d = 0; d <= depth; ++d) {ISDestroy(&nums[d]);}
6215:   return(0);
6216: }


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

6222:   Input Parameter:
6223: . dm - The DMPlex object

6225:   Output Parameter:
6226: . ranks - The rank field

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

6231:   Level: intermediate

6233: .seealso: DMView()
6234: @*/
6235: PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6236: {
6237:   DM             rdm;
6238:   PetscDS        prob;
6239:   PetscFE        fe;
6240:   PetscScalar   *r;
6241:   PetscMPIInt    rank;
6242:   PetscInt       dim, cStart, cEnd, c;

6246:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
6247:   DMClone(dm, &rdm);
6248:   DMGetDimension(rdm, &dim);
6249:   PetscFECreateDefault(rdm, dim, 1, PETSC_TRUE, NULL, -1, &fe);
6250:   PetscObjectSetName((PetscObject) fe, "rank");
6251:   DMGetDS(rdm, &prob);
6252:   PetscDSSetDiscretization(prob, 0, (PetscObject) fe);
6253:   PetscFEDestroy(&fe);
6254:   DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);
6255:   DMCreateGlobalVector(rdm, ranks);
6256:   PetscObjectSetName((PetscObject) *ranks, "partition");
6257:   VecGetArray(*ranks, &r);
6258:   for (c = cStart; c < cEnd; ++c) {
6259:     PetscScalar *lr;

6261:     DMPlexPointGlobalRef(rdm, c, r, &lr);
6262:     *lr = rank;
6263:   }
6264:   VecRestoreArray(*ranks, &r);
6265:   DMDestroy(&rdm);
6266:   return(0);
6267: }

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

6272:   Input Parameter:
6273: . dm - The DMPlex object

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

6277:   Level: developer

6279: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6280: @*/
6281: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6282: {
6283:   PetscSection    coneSection, supportSection;
6284:   const PetscInt *cone, *support;
6285:   PetscInt        coneSize, c, supportSize, s;
6286:   PetscInt        pStart, pEnd, p, csize, ssize;
6287:   PetscErrorCode  ierr;

6291:   DMPlexGetConeSection(dm, &coneSection);
6292:   DMPlexGetSupportSection(dm, &supportSection);
6293:   /* Check that point p is found in the support of its cone points, and vice versa */
6294:   DMPlexGetChart(dm, &pStart, &pEnd);
6295:   for (p = pStart; p < pEnd; ++p) {
6296:     DMPlexGetConeSize(dm, p, &coneSize);
6297:     DMPlexGetCone(dm, p, &cone);
6298:     for (c = 0; c < coneSize; ++c) {
6299:       PetscBool dup = PETSC_FALSE;
6300:       PetscInt  d;
6301:       for (d = c-1; d >= 0; --d) {
6302:         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6303:       }
6304:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6305:       DMPlexGetSupport(dm, cone[c], &support);
6306:       for (s = 0; s < supportSize; ++s) {
6307:         if (support[s] == p) break;
6308:       }
6309:       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6310:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);
6311:         for (s = 0; s < coneSize; ++s) {
6312:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);
6313:         }
6314:         PetscPrintf(PETSC_COMM_SELF, "\n");
6315:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);
6316:         for (s = 0; s < supportSize; ++s) {
6317:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);
6318:         }
6319:         PetscPrintf(PETSC_COMM_SELF, "\n");
6320:         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6321:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6322:       }
6323:     }
6324:     DMPlexGetSupportSize(dm, p, &supportSize);
6325:     DMPlexGetSupport(dm, p, &support);
6326:     for (s = 0; s < supportSize; ++s) {
6327:       DMPlexGetConeSize(dm, support[s], &coneSize);
6328:       DMPlexGetCone(dm, support[s], &cone);
6329:       for (c = 0; c < coneSize; ++c) {
6330:         if (cone[c] == p) break;
6331:       }
6332:       if (c >= coneSize) {
6333:         PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);
6334:         for (c = 0; c < supportSize; ++c) {
6335:           PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);
6336:         }
6337:         PetscPrintf(PETSC_COMM_SELF, "\n");
6338:         PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);
6339:         for (c = 0; c < coneSize; ++c) {
6340:           PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);
6341:         }
6342:         PetscPrintf(PETSC_COMM_SELF, "\n");
6343:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6344:       }
6345:     }
6346:   }
6347:   PetscSectionGetStorageSize(coneSection, &csize);
6348:   PetscSectionGetStorageSize(supportSection, &ssize);
6349:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6350:   return(0);
6351: }

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

6356:   Input Parameters:
6357: + dm - The DMPlex object
6358: . isSimplex - Are the cells simplices or tensor products
6359: - cellHeight - Normally 0

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

6363:   Level: developer

6365: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6366: @*/
6367: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6368: {
6369:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6374:   DMGetDimension(dm, &dim);
6375:   switch (dim) {
6376:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6377:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6378:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6379:   default:
6380:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6381:   }
6382:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6383:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6384:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6385:   cMax = cMax >= 0 ? cMax : cEnd;
6386:   for (c = cStart; c < cMax; ++c) {
6387:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6389:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6390:     for (cl = 0; cl < closureSize*2; cl += 2) {
6391:       const PetscInt p = closure[cl];
6392:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6393:     }
6394:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6395:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6396:   }
6397:   for (c = cMax; c < cEnd; ++c) {
6398:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6400:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6401:     for (cl = 0; cl < closureSize*2; cl += 2) {
6402:       const PetscInt p = closure[cl];
6403:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6404:     }
6405:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6406:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6407:   }
6408:   return(0);
6409: }

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

6414:   Input Parameters:
6415: + dm - The DMPlex object
6416: . isSimplex - Are the cells simplices or tensor products
6417: - cellHeight - Normally 0

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

6421:   Level: developer

6423: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6424: @*/
6425: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6426: {
6427:   PetscInt       pMax[4];
6428:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

6433:   DMGetDimension(dm, &dim);
6434:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6435:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6436:   for (h = cellHeight; h < dim; ++h) {
6437:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6438:     for (c = cStart; c < cEnd; ++c) {
6439:       const PetscInt *cone, *ornt, *faces;
6440:       PetscInt        numFaces, faceSize, coneSize,f;
6441:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6443:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6444:       DMPlexGetConeSize(dm, c, &coneSize);
6445:       DMPlexGetCone(dm, c, &cone);
6446:       DMPlexGetConeOrientation(dm, c, &ornt);
6447:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6448:       for (cl = 0; cl < closureSize*2; cl += 2) {
6449:         const PetscInt p = closure[cl];
6450:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6451:       }
6452:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6453:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6454:       for (f = 0; f < numFaces; ++f) {
6455:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6457:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6458:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6459:           const PetscInt p = fclosure[cl];
6460:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6461:         }
6462:         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);
6463:         for (v = 0; v < fnumCorners; ++v) {
6464:           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]);
6465:         }
6466:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6467:       }
6468:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6469:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6470:     }
6471:   }
6472:   return(0);
6473: }

6475: /* Pointwise interpolation
6476:      Just code FEM for now
6477:      u^f = I u^c
6478:      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
6479:      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
6480:      I_{ij} = psi^f_i phi^c_j
6481: */
6482: PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
6483: {
6484:   PetscSection   gsc, gsf;
6485:   PetscInt       m, n;
6486:   void          *ctx;
6487:   DM             cdm;
6488:   PetscBool      regular;

6492:   DMGetDefaultGlobalSection(dmFine, &gsf);
6493:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6494:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6495:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6497:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);
6498:   MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6499:   MatSetType(*interpolation, dmCoarse->mattype);
6500:   DMGetApplicationContext(dmFine, &ctx);

6502:   DMGetCoarseDM(dmFine, &cdm);
6503:   DMPlexGetRegularRefinement(dmFine, &regular);
6504:   if (regular && cdm == dmCoarse) {DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);}
6505:   else                            {DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);}
6506:   MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");
6507:   /* Use naive scaling */
6508:   DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);
6509:   return(0);
6510: }

6512: PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
6513: {
6515:   VecScatter     ctx;

6518:   DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);
6519:   MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);
6520:   VecScatterDestroy(&ctx);
6521:   return(0);
6522: }

6524: PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
6525: {
6526:   PetscSection   gsc, gsf;
6527:   PetscInt       m, n;
6528:   void          *ctx;
6529:   DM             cdm;
6530:   PetscBool      regular;

6534:   DMGetDefaultGlobalSection(dmFine, &gsf);
6535:   PetscSectionGetConstrainedStorageSize(gsf, &m);
6536:   DMGetDefaultGlobalSection(dmCoarse, &gsc);
6537:   PetscSectionGetConstrainedStorageSize(gsc, &n);

6539:   MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);
6540:   MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);
6541:   MatSetType(*mass, dmCoarse->mattype);
6542:   DMGetApplicationContext(dmFine, &ctx);

6544:   DMGetCoarseDM(dmFine, &cdm);
6545:   DMPlexGetRegularRefinement(dmFine, &regular);
6546:   if (regular && cdm == dmCoarse) {DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);}
6547:   else                            {DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);}
6548:   MatViewFromOptions(*mass, NULL, "-mass_mat_view");
6549:   return(0);
6550: }

6552: PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
6553: {
6554:   PetscSection   section;
6555:   IS            *bcPoints, *bcComps;
6556:   PetscBool     *isFE;
6557:   PetscInt      *bcFields, *numComp, *numDof;
6558:   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
6559:   PetscInt       cStart, cEnd, cEndInterior;

6563:   DMGetNumFields(dm, &numFields);
6564:   /* FE and FV boundary conditions are handled slightly differently */
6565:   PetscMalloc1(numFields, &isFE);
6566:   for (f = 0; f < numFields; ++f) {
6567:     PetscObject  obj;
6568:     PetscClassId id;

6570:     DMGetField(dm, f, &obj);
6571:     PetscObjectGetClassId(obj, &id);
6572:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
6573:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
6574:     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
6575:   }
6576:   /* Allocate boundary point storage for FEM boundaries */
6577:   DMPlexGetDepth(dm, &depth);
6578:   DMGetDimension(dm, &dim);
6579:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6580:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
6581:   PetscDSGetNumBoundary(dm->prob, &numBd);
6582:   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)");
6583:   for (bd = 0; bd < numBd; ++bd) {
6584:     PetscInt                field;
6585:     DMBoundaryConditionType type;
6586:     const char             *labelName;
6587:     DMLabel                 label;

6589:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);
6590:     DMGetLabel(dm,labelName,&label);
6591:     if (label && isFE[field] && (type & DM_BC_ESSENTIAL)) ++numBC;
6592:   }
6593:   /* Add ghost cell boundaries for FVM */
6594:   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
6595:   PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);
6596:   /* Constrain ghost cells for FV */
6597:   for (f = 0; f < numFields; ++f) {
6598:     PetscInt *newidx, c;

6600:     if (isFE[f] || cEndInterior < 0) continue;
6601:     PetscMalloc1(cEnd-cEndInterior,&newidx);
6602:     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
6603:     bcFields[bc] = f;
6604:     ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6605:   }
6606:   /* Handle FEM Dirichlet boundaries */
6607:   for (bd = 0; bd < numBd; ++bd) {
6608:     const char             *bdLabel;
6609:     DMLabel                 label;
6610:     const PetscInt         *comps;
6611:     const PetscInt         *values;
6612:     PetscInt                bd2, field, numComps, numValues;
6613:     DMBoundaryConditionType type;
6614:     PetscBool               duplicate = PETSC_FALSE;

6616:     PetscDSGetBoundary(dm->prob, bd, &type, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);
6617:     DMGetLabel(dm, bdLabel, &label);
6618:     if (!isFE[field] || !label) continue;
6619:     /* Only want to modify label once */
6620:     for (bd2 = 0; bd2 < bd; ++bd2) {
6621:       const char *bdname;
6622:       PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
6623:       PetscStrcmp(bdname, bdLabel, &duplicate);
6624:       if (duplicate) break;
6625:     }
6626:     if (!duplicate && (isFE[field])) {
6627:       /* don't complete cells, which are just present to give orientation to the boundary */
6628:       DMPlexLabelComplete(dm, label);
6629:     }
6630:     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
6631:     if (type & DM_BC_ESSENTIAL) {
6632:       PetscInt       *newidx;
6633:       PetscInt        n, newn = 0, p, v;

6635:       bcFields[bc] = field;
6636:       if (numComps) {ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);}
6637:       for (v = 0; v < numValues; ++v) {
6638:         IS              tmp;
6639:         const PetscInt *idx;

6641:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6642:         if (!tmp) continue;
6643:         ISGetLocalSize(tmp, &n);
6644:         ISGetIndices(tmp, &idx);
6645:         if (isFE[field]) {
6646:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6647:         } else {
6648:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
6649:         }
6650:         ISRestoreIndices(tmp, &idx);
6651:         ISDestroy(&tmp);
6652:       }
6653:       PetscMalloc1(newn,&newidx);
6654:       newn = 0;
6655:       for (v = 0; v < numValues; ++v) {
6656:         IS              tmp;
6657:         const PetscInt *idx;

6659:         DMGetStratumIS(dm, bdLabel, values[v], &tmp);
6660:         if (!tmp) continue;
6661:         ISGetLocalSize(tmp, &n);
6662:         ISGetIndices(tmp, &idx);
6663:         if (isFE[field]) {
6664:           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6665:         } else {
6666:           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
6667:         }
6668:         ISRestoreIndices(tmp, &idx);
6669:         ISDestroy(&tmp);
6670:       }
6671:       ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);
6672:     }
6673:   }
6674:   /* Handle discretization */
6675:   PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);
6676:   for (f = 0; f < numFields; ++f) {
6677:     PetscObject obj;

6679:     DMGetField(dm, f, &obj);
6680:     if (isFE[f]) {
6681:       PetscFE         fe = (PetscFE) obj;
6682:       const PetscInt *numFieldDof;
6683:       PetscInt        d;

6685:       PetscFEGetNumComponents(fe, &numComp[f]);
6686:       PetscFEGetNumDof(fe, &numFieldDof);
6687:       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6688:     } else {
6689:       PetscFV fv = (PetscFV) obj;

6691:       PetscFVGetNumComponents(fv, &numComp[f]);
6692:       numDof[f*(dim+1)+dim] = numComp[f];
6693:     }
6694:   }
6695:   for (f = 0; f < numFields; ++f) {
6696:     PetscInt d;
6697:     for (d = 1; d < dim; ++d) {
6698:       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.");
6699:     }
6700:   }
6701:   DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);
6702:   for (f = 0; f < numFields; ++f) {
6703:     PetscFE     fe;
6704:     const char *name;

6706:     DMGetField(dm, f, (PetscObject *) &fe);
6707:     PetscObjectGetName((PetscObject) fe, &name);
6708:     PetscSectionSetFieldName(section, f, name);
6709:   }
6710:   DMSetDefaultSection(dm, section);
6711:   PetscSectionDestroy(&section);
6712:   for (bc = 0; bc < numBC; ++bc) {ISDestroy(&bcPoints[bc]);ISDestroy(&bcComps[bc]);}
6713:   PetscFree3(bcFields,bcPoints,bcComps);
6714:   PetscFree2(numComp,numDof);
6715:   PetscFree(isFE);
6716:   return(0);
6717: }

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

6722:   Input Parameter:
6723: . dm - The DMPlex object

6725:   Output Parameter:
6726: . regular - The flag

6728:   Level: intermediate

6730: .seealso: DMPlexSetRegularRefinement()
6731: @*/
6732: PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
6733: {
6737:   *regular = ((DM_Plex *) dm->data)->regularRefinement;
6738:   return(0);
6739: }

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

6744:   Input Parameters:
6745: + dm - The DMPlex object
6746: - regular - The flag

6748:   Level: intermediate

6750: .seealso: DMPlexGetRegularRefinement()
6751: @*/
6752: PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6753: {
6756:   ((DM_Plex *) dm->data)->regularRefinement = regular;
6757:   return(0);
6758: }

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

6765:   not collective

6767:   Input Parameters:
6768: . dm - The DMPlex object

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


6775:   Level: intermediate

6777: .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6778: @*/
6779: PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6780: {
6781:   DM_Plex *plex = (DM_Plex *)dm->data;

6786:   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {(*plex->createanchors)(dm);}
6787:   if (anchorSection) *anchorSection = plex->anchorSection;
6788:   if (anchorIS) *anchorIS = plex->anchorIS;
6789:   return(0);
6790: }

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

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

6800:   collective on dm

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

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

6809:   Level: intermediate

6811: .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6812: @*/
6813: PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6814: {
6815:   DM_Plex        *plex = (DM_Plex *)dm->data;
6816:   PetscMPIInt    result;

6821:   if (anchorSection) {
6823:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);
6824:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6825:   }
6826:   if (anchorIS) {
6828:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);
6829:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6830:   }

6832:   PetscObjectReference((PetscObject)anchorSection);
6833:   PetscSectionDestroy(&plex->anchorSection);
6834:   plex->anchorSection = anchorSection;

6836:   PetscObjectReference((PetscObject)anchorIS);
6837:   ISDestroy(&plex->anchorIS);
6838:   plex->anchorIS = anchorIS;

6840: #if defined(PETSC_USE_DEBUG)
6841:   if (anchorIS && anchorSection) {
6842:     PetscInt size, a, pStart, pEnd;
6843:     const PetscInt *anchors;

6845:     PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6846:     ISGetLocalSize(anchorIS,&size);
6847:     ISGetIndices(anchorIS,&anchors);
6848:     for (a = 0; a < size; a++) {
6849:       PetscInt p;

6851:       p = anchors[a];
6852:       if (p >= pStart && p < pEnd) {
6853:         PetscInt dof;

6855:         PetscSectionGetDof(anchorSection,p,&dof);
6856:         if (dof) {
6857:           PetscErrorCode ierr2;

6859:           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6860:           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
6861:         }
6862:       }
6863:     }
6864:     ISRestoreIndices(anchorIS,&anchors);
6865:   }
6866: #endif
6867:   /* reset the generic constraints */
6868:   DMSetDefaultConstraints(dm,NULL,NULL);
6869:   return(0);
6870: }

6872: static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6873: {
6874:   PetscSection anchorSection;
6875:   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;

6880:   DMPlexGetAnchors(dm,&anchorSection,NULL);
6881:   PetscSectionCreate(PETSC_COMM_SELF,cSec);
6882:   PetscSectionGetNumFields(section,&numFields);
6883:   if (numFields) {
6884:     PetscInt f;
6885:     PetscSectionSetNumFields(*cSec,numFields);

6887:     for (f = 0; f < numFields; f++) {
6888:       PetscInt numComp;

6890:       PetscSectionGetFieldComponents(section,f,&numComp);
6891:       PetscSectionSetFieldComponents(*cSec,f,numComp);
6892:     }
6893:   }
6894:   PetscSectionGetChart(anchorSection,&pStart,&pEnd);
6895:   PetscSectionGetChart(section,&sStart,&sEnd);
6896:   pStart = PetscMax(pStart,sStart);
6897:   pEnd   = PetscMin(pEnd,sEnd);
6898:   pEnd   = PetscMax(pStart,pEnd);
6899:   PetscSectionSetChart(*cSec,pStart,pEnd);
6900:   for (p = pStart; p < pEnd; p++) {
6901:     PetscSectionGetDof(anchorSection,p,&dof);
6902:     if (dof) {
6903:       PetscSectionGetDof(section,p,&dof);
6904:       PetscSectionSetDof(*cSec,p,dof);
6905:       for (f = 0; f < numFields; f++) {
6906:         PetscSectionGetFieldDof(section,p,f,&dof);
6907:         PetscSectionSetFieldDof(*cSec,p,f,dof);
6908:       }
6909:     }
6910:   }
6911:   PetscSectionSetUp(*cSec);
6912:   return(0);
6913: }

6915: static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6916: {
6917:   PetscSection aSec;
6918:   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6919:   const PetscInt *anchors;
6920:   PetscInt numFields, f;
6921:   IS aIS;

6926:   PetscSectionGetStorageSize(cSec, &m);
6927:   PetscSectionGetStorageSize(section, &n);
6928:   MatCreate(PETSC_COMM_SELF,cMat);
6929:   MatSetSizes(*cMat,m,n,m,n);
6930:   MatSetType(*cMat,MATSEQAIJ);
6931:   DMPlexGetAnchors(dm,&aSec,&aIS);
6932:   ISGetIndices(aIS,&anchors);
6933:   /* cSec will be a subset of aSec and section */
6934:   PetscSectionGetChart(cSec,&pStart,&pEnd);
6935:   PetscMalloc1(m+1,&i);
6936:   i[0] = 0;
6937:   PetscSectionGetNumFields(section,&numFields);
6938:   for (p = pStart; p < pEnd; p++) {
6939:     PetscInt rDof, rOff, r;

6941:     PetscSectionGetDof(aSec,p,&rDof);
6942:     if (!rDof) continue;
6943:     PetscSectionGetOffset(aSec,p,&rOff);
6944:     if (numFields) {
6945:       for (f = 0; f < numFields; f++) {
6946:         annz = 0;
6947:         for (r = 0; r < rDof; r++) {
6948:           a = anchors[rOff + r];
6949:           PetscSectionGetFieldDof(section,a,f,&aDof);
6950:           annz += aDof;
6951:         }
6952:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6953:         PetscSectionGetFieldOffset(cSec,p,f,&off);
6954:         for (q = 0; q < dof; q++) {
6955:           i[off + q + 1] = i[off + q] + annz;
6956:         }
6957:       }
6958:     }
6959:     else {
6960:       annz = 0;
6961:       for (q = 0; q < dof; q++) {
6962:         a = anchors[off + q];
6963:         PetscSectionGetDof(section,a,&aDof);
6964:         annz += aDof;
6965:       }
6966:       PetscSectionGetDof(cSec,p,&dof);
6967:       PetscSectionGetOffset(cSec,p,&off);
6968:       for (q = 0; q < dof; q++) {
6969:         i[off + q + 1] = i[off + q] + annz;
6970:       }
6971:     }
6972:   }
6973:   nnz = i[m];
6974:   PetscMalloc1(nnz,&j);
6975:   offset = 0;
6976:   for (p = pStart; p < pEnd; p++) {
6977:     if (numFields) {
6978:       for (f = 0; f < numFields; f++) {
6979:         PetscSectionGetFieldDof(cSec,p,f,&dof);
6980:         for (q = 0; q < dof; q++) {
6981:           PetscInt rDof, rOff, r;
6982:           PetscSectionGetDof(aSec,p,&rDof);
6983:           PetscSectionGetOffset(aSec,p,&rOff);
6984:           for (r = 0; r < rDof; r++) {
6985:             PetscInt s;

6987:             a = anchors[rOff + r];
6988:             PetscSectionGetFieldDof(section,a,f,&aDof);
6989:             PetscSectionGetFieldOffset(section,a,f,&aOff);
6990:             for (s = 0; s < aDof; s++) {
6991:               j[offset++] = aOff + s;
6992:             }
6993:           }
6994:         }
6995:       }
6996:     }
6997:     else {
6998:       PetscSectionGetDof(cSec,p,&dof);
6999:       for (q = 0; q < dof; q++) {
7000:         PetscInt rDof, rOff, r;
7001:         PetscSectionGetDof(aSec,p,&rDof);
7002:         PetscSectionGetOffset(aSec,p,&rOff);
7003:         for (r = 0; r < rDof; r++) {
7004:           PetscInt s;

7006:           a = anchors[rOff + r];
7007:           PetscSectionGetDof(section,a,&aDof);
7008:           PetscSectionGetOffset(section,a,&aOff);
7009:           for (s = 0; s < aDof; s++) {
7010:             j[offset++] = aOff + s;
7011:           }
7012:         }
7013:       }
7014:     }
7015:   }
7016:   MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);
7017:   PetscFree(i);
7018:   PetscFree(j);
7019:   ISRestoreIndices(aIS,&anchors);
7020:   return(0);
7021: }

7023: PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7024: {
7025:   DM_Plex        *plex = (DM_Plex *)dm->data;
7026:   PetscSection   anchorSection, section, cSec;
7027:   Mat            cMat;

7032:   DMPlexGetAnchors(dm,&anchorSection,NULL);
7033:   if (anchorSection) {
7034:     PetscDS  ds;
7035:     PetscInt nf;

7037:     DMGetDefaultSection(dm,&section);
7038:     DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);
7039:     DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);
7040:     DMGetDS(dm,&ds);
7041:     PetscDSGetNumFields(ds,&nf);
7042:     if (nf && plex->computeanchormatrix) {(*plex->computeanchormatrix)(dm,section,cSec,cMat);}
7043:     DMSetDefaultConstraints(dm,cSec,cMat);
7044:     PetscSectionDestroy(&cSec);
7045:     MatDestroy(&cMat);
7046:   }
7047:   return(0);
7048: }