Actual source code: plex.c

  1: #include <petsc/private/dmpleximpl.h>
  2: #include <petsc/private/dmlabelimpl.h>
  3: #include <petsc/private/isimpl.h>
  4: #include <petsc/private/vecimpl.h>
  5: #include <petsc/private/glvisvecimpl.h>
  6: #include <petscsf.h>
  7: #include <petscds.h>
  8: #include <petscdraw.h>
  9: #include <petscdmfield.h>
 10: #include <petscdmplextransform.h>

 12: /* Logging support */
 13: PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad;
 14: PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate;

 16: PetscBool  Plexcite       = PETSC_FALSE;
 17: const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n"
 18:                             "title     = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n"
 19:                             "author    = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n"
 20:                             "journal   = {SIAM Journal on Scientific Computing},\n"
 21:                             "volume    = {38},\n"
 22:                             "number    = {5},\n"
 23:                             "pages     = {S143--S155},\n"
 24:                             "eprint    = {http://arxiv.org/abs/1506.07749},\n"
 25:                             "doi       = {10.1137/15M1026092},\n"
 26:                             "year      = {2016},\n"
 27:                             "petsc_uses={DMPlex},\n}\n";

 29: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

 31: /*@
 32:   DMPlexIsSimplex - Is the first cell in this mesh a simplex?

 34:   Input Parameter:
 35: . dm - The `DMPLEX` object

 37:   Output Parameter:
 38: . simplex - Flag checking for a simplex

 40:   Level: intermediate

 42:   Note:
 43:   This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
 44:   If the mesh has no cells, this returns `PETSC_FALSE`.

 46: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()`
 47: @*/
 48: PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
 49: {
 50:   DMPolytopeType ct;
 51:   PetscInt       cStart, cEnd;

 53:   PetscFunctionBegin;
 54:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
 55:   if (cEnd <= cStart) {
 56:     *simplex = PETSC_FALSE;
 57:     PetscFunctionReturn(PETSC_SUCCESS);
 58:   }
 59:   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
 60:   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
 61:   PetscFunctionReturn(PETSC_SUCCESS);
 62: }

 64: /*@
 65:   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells

 67:   Input Parameters:
 68: + dm     - The `DMPLEX` object
 69: - height - The cell height in the Plex, 0 is the default

 71:   Output Parameters:
 72: + cStart - The first "normal" cell
 73: - cEnd   - The upper bound on "normal"" cells

 75:   Level: developer

 77:   Note:
 78:   This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.

 80: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()`
 81: @*/
 82: PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
 83: {
 84:   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
 85:   PetscInt       cS, cE, c;

 87:   PetscFunctionBegin;
 88:   PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE));
 89:   for (c = cS; c < cE; ++c) {
 90:     DMPolytopeType cct;

 92:     PetscCall(DMPlexGetCellType(dm, c, &cct));
 93:     if ((PetscInt)cct < 0) break;
 94:     switch (cct) {
 95:     case DM_POLYTOPE_POINT:
 96:     case DM_POLYTOPE_SEGMENT:
 97:     case DM_POLYTOPE_TRIANGLE:
 98:     case DM_POLYTOPE_QUADRILATERAL:
 99:     case DM_POLYTOPE_TETRAHEDRON:
100:     case DM_POLYTOPE_HEXAHEDRON:
101:       ct = cct;
102:       break;
103:     default:
104:       break;
105:     }
106:     if (ct != DM_POLYTOPE_UNKNOWN) break;
107:   }
108:   if (ct != DM_POLYTOPE_UNKNOWN) {
109:     DMLabel ctLabel;

111:     PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
112:     PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE));
113:     // Reset label for fast lookup
114:     PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
115:   }
116:   if (cStart) *cStart = cS;
117:   if (cEnd) *cEnd = cE;
118:   PetscFunctionReturn(PETSC_SUCCESS);
119: }

121: PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
122: {
123:   PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
124:   PetscInt vcdof[2] = {0, 0}, globalvcdof[2];

126:   PetscFunctionBegin;
127:   *ft = PETSC_VTK_INVALID;
128:   PetscCall(DMGetCoordinateDim(dm, &cdim));
129:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
130:   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
131:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
132:   if (field >= 0) {
133:     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]));
134:     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]));
135:   } else {
136:     if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0]));
137:     if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1]));
138:   }
139:   PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
140:   if (globalvcdof[0]) {
141:     *sStart = vStart;
142:     *sEnd   = vEnd;
143:     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
144:     else *ft = PETSC_VTK_POINT_FIELD;
145:   } else if (globalvcdof[1]) {
146:     *sStart = cStart;
147:     *sEnd   = cEnd;
148:     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
149:     else *ft = PETSC_VTK_CELL_FIELD;
150:   } else {
151:     if (field >= 0) {
152:       const char *fieldname;

154:       PetscCall(PetscSectionGetFieldName(section, field, &fieldname));
155:       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname));
156:     } else {
157:       PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n"));
158:     }
159:   }
160:   PetscFunctionReturn(PETSC_SUCCESS);
161: }

163: /*@
164:   DMPlexVecView1D - Plot many 1D solutions on the same line graph

166:   Collective

168:   Input Parameters:
169: + dm     - The `DMPLEX` object
170: . n      - The number of vectors
171: . u      - The array of local vectors
172: - viewer - The `PetscViewer`

174:   Level: advanced

176: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()`
177: @*/
178: PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer)
179: {
180:   PetscDS            ds;
181:   PetscDraw          draw = NULL;
182:   PetscDrawLG        lg;
183:   Vec                coordinates;
184:   const PetscScalar *coords, **sol;
185:   PetscReal         *vals;
186:   PetscInt          *Nc;
187:   PetscInt           Nf, f, c, Nl, l, i, vStart, vEnd, v;
188:   char             **names;

190:   PetscFunctionBegin;
191:   PetscCall(DMGetDS(dm, &ds));
192:   PetscCall(PetscDSGetNumFields(ds, &Nf));
193:   PetscCall(PetscDSGetTotalComponents(ds, &Nl));
194:   PetscCall(PetscDSGetComponents(ds, &Nc));

196:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
197:   if (!draw) PetscFunctionReturn(PETSC_SUCCESS);
198:   PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg));

200:   PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals));
201:   for (i = 0, l = 0; i < n; ++i) {
202:     const char *vname;

204:     PetscCall(PetscObjectGetName((PetscObject)u[i], &vname));
205:     for (f = 0; f < Nf; ++f) {
206:       PetscObject disc;
207:       const char *fname;
208:       char        tmpname[PETSC_MAX_PATH_LEN];

210:       PetscCall(PetscDSGetDiscretization(ds, f, &disc));
211:       /* TODO Create names for components */
212:       for (c = 0; c < Nc[f]; ++c, ++l) {
213:         PetscCall(PetscObjectGetName(disc, &fname));
214:         PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname)));
215:         PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname)));
216:         PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname)));
217:         PetscCall(PetscStrallocpy(tmpname, &names[l]));
218:       }
219:     }
220:   }
221:   PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names));
222:   /* Just add P_1 support for now */
223:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
224:   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
225:   PetscCall(VecGetArrayRead(coordinates, &coords));
226:   for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i]));
227:   for (v = vStart; v < vEnd; ++v) {
228:     PetscScalar *x, *svals;

230:     PetscCall(DMPlexPointLocalRead(dm, v, coords, &x));
231:     for (i = 0; i < n; ++i) {
232:       PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals));
233:       for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]);
234:     }
235:     PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals));
236:   }
237:   PetscCall(VecRestoreArrayRead(coordinates, &coords));
238:   for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i]));
239:   for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l]));
240:   PetscCall(PetscFree3(sol, names, vals));

242:   PetscCall(PetscDrawLGDraw(lg));
243:   PetscCall(PetscDrawLGDestroy(&lg));
244:   PetscFunctionReturn(PETSC_SUCCESS);
245: }

247: static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer)
248: {
249:   DM dm;

251:   PetscFunctionBegin;
252:   PetscCall(VecGetDM(u, &dm));
253:   PetscCall(DMPlexVecView1D(dm, 1, &u, viewer));
254:   PetscFunctionReturn(PETSC_SUCCESS);
255: }

257: static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer)
258: {
259:   DM                 dm;
260:   PetscSection       s;
261:   PetscDraw          draw, popup;
262:   DM                 cdm;
263:   PetscSection       coordSection;
264:   Vec                coordinates;
265:   const PetscScalar *array;
266:   PetscReal          lbound[3], ubound[3];
267:   PetscReal          vbound[2], time;
268:   PetscBool          flg;
269:   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
270:   const char        *name;
271:   char               title[PETSC_MAX_PATH_LEN];

273:   PetscFunctionBegin;
274:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
275:   PetscCall(VecGetDM(v, &dm));
276:   PetscCall(DMGetCoordinateDim(dm, &dim));
277:   PetscCall(DMGetLocalSection(dm, &s));
278:   PetscCall(PetscSectionGetNumFields(s, &Nf));
279:   PetscCall(DMGetCoarsenLevel(dm, &level));
280:   PetscCall(DMGetCoordinateDM(dm, &cdm));
281:   PetscCall(DMGetLocalSection(cdm, &coordSection));
282:   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
283:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
284:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));

286:   PetscCall(PetscObjectGetName((PetscObject)v, &name));
287:   PetscCall(DMGetOutputSequenceNumber(dm, &step, &time));

289:   PetscCall(VecGetLocalSize(coordinates, &N));
290:   PetscCall(DMGetBoundingBox(dm, lbound, ubound));
291:   PetscCall(PetscDrawClear(draw));

293:   /* Could implement something like DMDASelectFields() */
294:   for (f = 0; f < Nf; ++f) {
295:     DM          fdm = dm;
296:     Vec         fv  = v;
297:     IS          fis;
298:     char        prefix[PETSC_MAX_PATH_LEN];
299:     const char *fname;

301:     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
302:     PetscCall(PetscSectionGetFieldName(s, f, &fname));

304:     if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix)));
305:     else prefix[0] = '\0';
306:     if (Nf > 1) {
307:       PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm));
308:       PetscCall(VecGetSubVector(v, fis, &fv));
309:       PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix)));
310:       PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix)));
311:     }
312:     for (comp = 0; comp < Nc; ++comp, ++w) {
313:       PetscInt nmax = 2;

315:       PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw));
316:       if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time));
317:       else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time));
318:       PetscCall(PetscDrawSetTitle(draw, title));

320:       /* TODO Get max and min only for this component */
321:       PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg));
322:       if (!flg) {
323:         PetscCall(VecMin(fv, NULL, &vbound[0]));
324:         PetscCall(VecMax(fv, NULL, &vbound[1]));
325:         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
326:       }

328:       PetscCall(PetscDrawGetPopup(draw, &popup));
329:       PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1]));
330:       PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1]));
331:       PetscCall(VecGetArrayRead(fv, &array));
332:       for (c = cStart; c < cEnd; ++c) {
333:         PetscScalar       *coords = NULL, *a = NULL;
334:         const PetscScalar *coords_arr;
335:         PetscBool          isDG;
336:         PetscInt           numCoords, color[4] = {-1, -1, -1, -1};

338:         PetscCall(DMPlexPointLocalRead(fdm, c, array, &a));
339:         if (a) {
340:           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
341:           color[1] = color[2] = color[3] = color[0];
342:         } else {
343:           PetscScalar *vals = NULL;
344:           PetscInt     numVals, va;

346:           PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals));
347:           PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals);
348:           switch (numVals / Nc) {
349:           case 3: /* P1 Triangle */
350:           case 4: /* P1 Quadrangle */
351:             for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]);
352:             break;
353:           case 6: /* P2 Triangle */
354:           case 8: /* P2 Quadrangle */
355:             for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]);
356:             break;
357:           default:
358:             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc);
359:           }
360:           PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals));
361:         }
362:         PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
363:         switch (numCoords) {
364:         case 6:
365:         case 12: /* Localized triangle */
366:           PetscCall(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]));
367:           break;
368:         case 8:
369:         case 16: /* Localized quadrilateral */
370:           PetscCall(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]));
371:           PetscCall(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]));
372:           break;
373:         default:
374:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords);
375:         }
376:         PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
377:       }
378:       PetscCall(VecRestoreArrayRead(fv, &array));
379:       PetscCall(PetscDrawFlush(draw));
380:       PetscCall(PetscDrawPause(draw));
381:       PetscCall(PetscDrawSave(draw));
382:     }
383:     if (Nf > 1) {
384:       PetscCall(VecRestoreSubVector(v, fis, &fv));
385:       PetscCall(ISDestroy(&fis));
386:       PetscCall(DMDestroy(&fdm));
387:     }
388:   }
389:   PetscFunctionReturn(PETSC_SUCCESS);
390: }

392: static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
393: {
394:   DM        dm;
395:   PetscDraw draw;
396:   PetscInt  dim;
397:   PetscBool isnull;

399:   PetscFunctionBegin;
400:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
401:   PetscCall(PetscDrawIsNull(draw, &isnull));
402:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);

404:   PetscCall(VecGetDM(v, &dm));
405:   PetscCall(DMGetCoordinateDim(dm, &dim));
406:   switch (dim) {
407:   case 1:
408:     PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));
409:     break;
410:   case 2:
411:     PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));
412:     break;
413:   default:
414:     SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim);
415:   }
416:   PetscFunctionReturn(PETSC_SUCCESS);
417: }

419: static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
420: {
421:   DM                      dm;
422:   Vec                     locv;
423:   const char             *name;
424:   PetscSection            section;
425:   PetscInt                pStart, pEnd;
426:   PetscInt                numFields;
427:   PetscViewerVTKFieldType ft;

429:   PetscFunctionBegin;
430:   PetscCall(VecGetDM(v, &dm));
431:   PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */
432:   PetscCall(PetscObjectGetName((PetscObject)v, &name));
433:   PetscCall(PetscObjectSetName((PetscObject)locv, name));
434:   PetscCall(VecCopy(v, locv));
435:   PetscCall(DMGetLocalSection(dm, &section));
436:   PetscCall(PetscSectionGetNumFields(section, &numFields));
437:   if (!numFields) {
438:     PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft));
439:     PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv));
440:   } else {
441:     PetscInt f;

443:     for (f = 0; f < numFields; f++) {
444:       PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft));
445:       if (ft == PETSC_VTK_INVALID) continue;
446:       PetscCall(PetscObjectReference((PetscObject)locv));
447:       PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv));
448:     }
449:     PetscCall(VecDestroy(&locv));
450:   }
451:   PetscFunctionReturn(PETSC_SUCCESS);
452: }

454: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
455: {
456:   DM        dm;
457:   PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns;

459:   PetscFunctionBegin;
460:   PetscCall(VecGetDM(v, &dm));
461:   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
462:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
463:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
464:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
465:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
466:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
467:   if (isvtk || ishdf5 || isdraw || isglvis || iscgns) {
468:     PetscInt    i, numFields;
469:     PetscObject fe;
470:     PetscBool   fem  = PETSC_FALSE;
471:     Vec         locv = v;
472:     const char *name;
473:     PetscInt    step;
474:     PetscReal   time;

476:     PetscCall(DMGetNumFields(dm, &numFields));
477:     for (i = 0; i < numFields; i++) {
478:       PetscCall(DMGetField(dm, i, NULL, &fe));
479:       if (fe->classid == PETSCFE_CLASSID) {
480:         fem = PETSC_TRUE;
481:         break;
482:       }
483:     }
484:     if (fem) {
485:       PetscObject isZero;

487:       PetscCall(DMGetLocalVector(dm, &locv));
488:       PetscCall(PetscObjectGetName((PetscObject)v, &name));
489:       PetscCall(PetscObjectSetName((PetscObject)locv, name));
490:       PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
491:       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
492:       PetscCall(VecCopy(v, locv));
493:       PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
494:       PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL));
495:     }
496:     if (isvtk) {
497:       PetscCall(VecView_Plex_Local_VTK(locv, viewer));
498:     } else if (ishdf5) {
499: #if defined(PETSC_HAVE_HDF5)
500:       PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer));
501: #else
502:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
503: #endif
504:     } else if (isdraw) {
505:       PetscCall(VecView_Plex_Local_Draw(locv, viewer));
506:     } else if (isglvis) {
507:       PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL));
508:       PetscCall(PetscViewerGLVisSetSnapId(viewer, step));
509:       PetscCall(VecView_GLVis(locv, viewer));
510:     } else if (iscgns) {
511: #if defined(PETSC_HAVE_CGNS)
512:       PetscCall(VecView_Plex_Local_CGNS(locv, viewer));
513: #else
514:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns");
515: #endif
516:     }
517:     if (fem) {
518:       PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
519:       PetscCall(DMRestoreLocalVector(dm, &locv));
520:     }
521:   } else {
522:     PetscBool isseq;

524:     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
525:     if (isseq) PetscCall(VecView_Seq(v, viewer));
526:     else PetscCall(VecView_MPI(v, viewer));
527:   }
528:   PetscFunctionReturn(PETSC_SUCCESS);
529: }

531: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
532: {
533:   DM        dm;
534:   PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns;

536:   PetscFunctionBegin;
537:   PetscCall(VecGetDM(v, &dm));
538:   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
539:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
540:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
541:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
542:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
543:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
544:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
545:   if (isvtk || isdraw || isglvis || iscgns) {
546:     Vec         locv;
547:     PetscObject isZero;
548:     const char *name;

550:     PetscCall(DMGetLocalVector(dm, &locv));
551:     PetscCall(PetscObjectGetName((PetscObject)v, &name));
552:     PetscCall(PetscObjectSetName((PetscObject)locv, name));
553:     PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv));
554:     PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv));
555:     PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero));
556:     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero));
557:     PetscCall(VecView_Plex_Local(locv, viewer));
558:     PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL));
559:     PetscCall(DMRestoreLocalVector(dm, &locv));
560:   } else if (ishdf5) {
561: #if defined(PETSC_HAVE_HDF5)
562:     PetscCall(VecView_Plex_HDF5_Internal(v, viewer));
563: #else
564:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
565: #endif
566:   } else if (isexodusii) {
567: #if defined(PETSC_HAVE_EXODUSII)
568:     PetscCall(VecView_PlexExodusII_Internal(v, viewer));
569: #else
570:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
571: #endif
572:   } else {
573:     PetscBool isseq;

575:     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
576:     if (isseq) PetscCall(VecView_Seq(v, viewer));
577:     else PetscCall(VecView_MPI(v, viewer));
578:   }
579:   PetscFunctionReturn(PETSC_SUCCESS);
580: }

582: PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
583: {
584:   DM                dm;
585:   MPI_Comm          comm;
586:   PetscViewerFormat format;
587:   Vec               v;
588:   PetscBool         isvtk, ishdf5;

590:   PetscFunctionBegin;
591:   PetscCall(VecGetDM(originalv, &dm));
592:   PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm));
593:   PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
594:   PetscCall(PetscViewerGetFormat(viewer, &format));
595:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
596:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
597:   if (format == PETSC_VIEWER_NATIVE) {
598:     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
599:     /* this need a better fix */
600:     if (dm->useNatural) {
601:       if (dm->sfNatural) {
602:         const char *vecname;
603:         PetscInt    n, nroots;

605:         PetscCall(VecGetLocalSize(originalv, &n));
606:         PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL));
607:         if (n == nroots) {
608:           PetscCall(DMPlexCreateNaturalVector(dm, &v));
609:           PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v));
610:           PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v));
611:           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
612:           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
613:         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
614:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
615:     } else v = originalv;
616:   } else v = originalv;

618:   if (ishdf5) {
619: #if defined(PETSC_HAVE_HDF5)
620:     PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer));
621: #else
622:     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
623: #endif
624:   } else if (isvtk) {
625:     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
626:   } else {
627:     PetscBool isseq;

629:     PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq));
630:     if (isseq) PetscCall(VecView_Seq(v, viewer));
631:     else PetscCall(VecView_MPI(v, viewer));
632:   }
633:   if (v != originalv) PetscCall(VecDestroy(&v));
634:   PetscFunctionReturn(PETSC_SUCCESS);
635: }

637: PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
638: {
639:   DM        dm;
640:   PetscBool ishdf5;

642:   PetscFunctionBegin;
643:   PetscCall(VecGetDM(v, &dm));
644:   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
645:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
646:   if (ishdf5) {
647:     DM          dmBC;
648:     Vec         gv;
649:     const char *name;

651:     PetscCall(DMGetOutputDM(dm, &dmBC));
652:     PetscCall(DMGetGlobalVector(dmBC, &gv));
653:     PetscCall(PetscObjectGetName((PetscObject)v, &name));
654:     PetscCall(PetscObjectSetName((PetscObject)gv, name));
655:     PetscCall(VecLoad_Default(gv, viewer));
656:     PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v));
657:     PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v));
658:     PetscCall(DMRestoreGlobalVector(dmBC, &gv));
659:   } else PetscCall(VecLoad_Default(v, viewer));
660:   PetscFunctionReturn(PETSC_SUCCESS);
661: }

663: PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
664: {
665:   DM        dm;
666:   PetscBool ishdf5, isexodusii;

668:   PetscFunctionBegin;
669:   PetscCall(VecGetDM(v, &dm));
670:   PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
671:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
672:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii));
673:   if (ishdf5) {
674: #if defined(PETSC_HAVE_HDF5)
675:     PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer));
676: #else
677:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
678: #endif
679:   } else if (isexodusii) {
680: #if defined(PETSC_HAVE_EXODUSII)
681:     PetscCall(VecLoad_PlexExodusII_Internal(v, viewer));
682: #else
683:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
684: #endif
685:   } else PetscCall(VecLoad_Default(v, viewer));
686:   PetscFunctionReturn(PETSC_SUCCESS);
687: }

689: PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
690: {
691:   DM                dm;
692:   PetscViewerFormat format;
693:   PetscBool         ishdf5;

695:   PetscFunctionBegin;
696:   PetscCall(VecGetDM(originalv, &dm));
697:   PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
698:   PetscCall(PetscViewerGetFormat(viewer, &format));
699:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
700:   if (format == PETSC_VIEWER_NATIVE) {
701:     if (dm->useNatural) {
702:       if (dm->sfNatural) {
703:         if (ishdf5) {
704: #if defined(PETSC_HAVE_HDF5)
705:           Vec         v;
706:           const char *vecname;

708:           PetscCall(DMPlexCreateNaturalVector(dm, &v));
709:           PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname));
710:           PetscCall(PetscObjectSetName((PetscObject)v, vecname));
711:           PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer));
712:           PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv));
713:           PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv));
714:           PetscCall(VecDestroy(&v));
715: #else
716:           SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
717: #endif
718:         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
719:       }
720:     } else PetscCall(VecLoad_Default(originalv, viewer));
721:   }
722:   PetscFunctionReturn(PETSC_SUCCESS);
723: }

725: PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
726: {
727:   PetscSection       coordSection;
728:   Vec                coordinates;
729:   DMLabel            depthLabel, celltypeLabel;
730:   const char        *name[4];
731:   const PetscScalar *a;
732:   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;

734:   PetscFunctionBegin;
735:   PetscCall(DMGetDimension(dm, &dim));
736:   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
737:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
738:   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
739:   PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel));
740:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
741:   PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd));
742:   PetscCall(VecGetArrayRead(coordinates, &a));
743:   name[0]       = "vertex";
744:   name[1]       = "edge";
745:   name[dim - 1] = "face";
746:   name[dim]     = "cell";
747:   for (c = cStart; c < cEnd; ++c) {
748:     PetscInt *closure = NULL;
749:     PetscInt  closureSize, cl, ct;

751:     PetscCall(DMLabelGetValue(celltypeLabel, c, &ct));
752:     PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct]));
753:     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
754:     PetscCall(PetscViewerASCIIPushTab(viewer));
755:     for (cl = 0; cl < closureSize * 2; cl += 2) {
756:       PetscInt point = closure[cl], depth, dof, off, d, p;

758:       if ((point < pStart) || (point >= pEnd)) continue;
759:       PetscCall(PetscSectionGetDof(coordSection, point, &dof));
760:       if (!dof) continue;
761:       PetscCall(DMLabelGetValue(depthLabel, point, &depth));
762:       PetscCall(PetscSectionGetOffset(coordSection, point, &off));
763:       PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point));
764:       for (p = 0; p < dof / dim; ++p) {
765:         PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
766:         for (d = 0; d < dim; ++d) {
767:           if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
768:           PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d])));
769:         }
770:         PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
771:       }
772:       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
773:     }
774:     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
775:     PetscCall(PetscViewerASCIIPopTab(viewer));
776:   }
777:   PetscCall(VecRestoreArrayRead(coordinates, &a));
778:   PetscFunctionReturn(PETSC_SUCCESS);
779: }

781: typedef enum {
782:   CS_CARTESIAN,
783:   CS_POLAR,
784:   CS_CYLINDRICAL,
785:   CS_SPHERICAL
786: } CoordSystem;
787: const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};

789: static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
790: {
791:   PetscInt i;

793:   PetscFunctionBegin;
794:   if (dim > 3) {
795:     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i])));
796:   } else {
797:     PetscReal coords[3], trcoords[3] = {0., 0., 0.};

799:     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
800:     switch (cs) {
801:     case CS_CARTESIAN:
802:       for (i = 0; i < dim; ++i) trcoords[i] = coords[i];
803:       break;
804:     case CS_POLAR:
805:       PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim);
806:       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
807:       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
808:       break;
809:     case CS_CYLINDRICAL:
810:       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
811:       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
812:       trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
813:       trcoords[2] = coords[2];
814:       break;
815:     case CS_SPHERICAL:
816:       PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim);
817:       trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
818:       trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
819:       trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
820:       break;
821:     }
822:     for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i]));
823:   }
824:   PetscFunctionReturn(PETSC_SUCCESS);
825: }

827: static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
828: {
829:   DM_Plex          *mesh = (DM_Plex *)dm->data;
830:   DM                cdm, cdmCell;
831:   PetscSection      coordSection, coordSectionCell;
832:   Vec               coordinates, coordinatesCell;
833:   PetscViewerFormat format;

835:   PetscFunctionBegin;
836:   PetscCall(PetscViewerGetFormat(viewer, &format));
837:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
838:     const char *name;
839:     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
840:     PetscInt    pStart, pEnd, p, numLabels, l;
841:     PetscMPIInt rank, size;

843:     PetscCall(DMGetCoordinateDM(dm, &cdm));
844:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
845:     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
846:     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
847:     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
848:     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
849:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
850:     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
851:     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
852:     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
853:     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
854:     PetscCall(DMGetDimension(dm, &dim));
855:     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
856:     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
857:     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
858:     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
859:     PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n"));
860:     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
861:     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize));
862:     for (p = pStart; p < pEnd; ++p) {
863:       PetscInt dof, off, s;

865:       PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
866:       PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
867:       for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s]));
868:     }
869:     PetscCall(PetscViewerFlush(viewer));
870:     PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n"));
871:     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize));
872:     for (p = pStart; p < pEnd; ++p) {
873:       PetscInt dof, off, c;

875:       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
876:       PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
877:       for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]));
878:     }
879:     PetscCall(PetscViewerFlush(viewer));
880:     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
881:     if (coordSection && coordinates) {
882:       CoordSystem        cs = CS_CARTESIAN;
883:       const PetscScalar *array, *arrayCell = NULL;
884:       PetscInt           Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p;
885:       PetscMPIInt        rank;
886:       const char        *name;

888:       PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL));
889:       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
890:       PetscCall(PetscSectionGetNumFields(coordSection, &Nf));
891:       PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf);
892:       PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
893:       PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd));
894:       if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd));
895:       pStart = PetscMin(pvStart, pcStart);
896:       pEnd   = PetscMax(pvEnd, pcEnd);
897:       PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
898:       PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf));
899:       PetscCall(PetscViewerASCIIPrintf(viewer, "  field 0 with %" PetscInt_FMT " components\n", Nc));
900:       if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]));

902:       PetscCall(VecGetArrayRead(coordinates, &array));
903:       if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell));
904:       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
905:       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
906:       for (p = pStart; p < pEnd; ++p) {
907:         PetscInt dof, off;

909:         if (p >= pvStart && p < pvEnd) {
910:           PetscCall(PetscSectionGetDof(coordSection, p, &dof));
911:           PetscCall(PetscSectionGetOffset(coordSection, p, &off));
912:           if (dof) {
913:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
914:             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]));
915:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
916:           }
917:         }
918:         if (cdmCell && p >= pcStart && p < pcEnd) {
919:           PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof));
920:           PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off));
921:           if (dof) {
922:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off));
923:             PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off]));
924:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
925:           }
926:         }
927:       }
928:       PetscCall(PetscViewerFlush(viewer));
929:       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
930:       PetscCall(VecRestoreArrayRead(coordinates, &array));
931:       if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell));
932:     }
933:     PetscCall(DMGetNumLabels(dm, &numLabels));
934:     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
935:     for (l = 0; l < numLabels; ++l) {
936:       DMLabel     label;
937:       PetscBool   isdepth;
938:       const char *name;

940:       PetscCall(DMGetLabelName(dm, l, &name));
941:       PetscCall(PetscStrcmp(name, "depth", &isdepth));
942:       if (isdepth) continue;
943:       PetscCall(DMGetLabel(dm, name, &label));
944:       PetscCall(DMLabelView(label, viewer));
945:     }
946:     if (size > 1) {
947:       PetscSF sf;

949:       PetscCall(DMGetPointSF(dm, &sf));
950:       PetscCall(PetscSFView(sf, viewer));
951:     }
952:     if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer));
953:     PetscCall(PetscViewerFlush(viewer));
954:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
955:     const char  *name, *color;
956:     const char  *defcolors[3]  = {"gray", "orange", "green"};
957:     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
958:     char         lname[PETSC_MAX_PATH_LEN];
959:     PetscReal    scale      = 2.0;
960:     PetscReal    tikzscale  = 1.0;
961:     PetscBool    useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
962:     double       tcoords[3];
963:     PetscScalar *coords;
964:     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
965:     PetscMPIInt  rank, size;
966:     char       **names, **colors, **lcolors;
967:     PetscBool    flg, lflg;
968:     PetscBT      wp = NULL;
969:     PetscInt     pEnd, pStart;

971:     PetscCall(DMGetCoordinateDM(dm, &cdm));
972:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
973:     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
974:     PetscCall(DMGetCellCoordinateDM(dm, &cdmCell));
975:     PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell));
976:     PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell));
977:     PetscCall(DMGetDimension(dm, &dim));
978:     PetscCall(DMPlexGetDepth(dm, &depth));
979:     PetscCall(DMGetNumLabels(dm, &numLabels));
980:     numLabels  = PetscMax(numLabels, 10);
981:     numColors  = 10;
982:     numLColors = 10;
983:     PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors));
984:     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL));
985:     PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL));
986:     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL));
987:     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
988:     for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE;
989:     n = 4;
990:     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg));
991:     PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1);
992:     PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg));
993:     PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1);
994:     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels));
995:     if (!useLabels) numLabels = 0;
996:     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors));
997:     if (!useColors) {
998:       numColors = 3;
999:       for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c]));
1000:     }
1001:     PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors));
1002:     if (!useColors) {
1003:       numLColors = 4;
1004:       for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c]));
1005:     }
1006:     PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg));
1007:     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
1008:     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg));
1009:     PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated");
1010:     if (depth < dim) plotEdges = PETSC_FALSE;
1011:     PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL));

1013:     /* filter points with labelvalue != labeldefaultvalue */
1014:     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1015:     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1016:     PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd));
1017:     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1018:     if (lflg) {
1019:       DMLabel lbl;

1021:       PetscCall(DMGetLabel(dm, lname, &lbl));
1022:       if (lbl) {
1023:         PetscInt val, defval;

1025:         PetscCall(DMLabelGetDefaultValue(lbl, &defval));
1026:         PetscCall(PetscBTCreate(pEnd - pStart, &wp));
1027:         for (c = pStart; c < pEnd; c++) {
1028:           PetscInt *closure = NULL;
1029:           PetscInt  closureSize;

1031:           PetscCall(DMLabelGetValue(lbl, c, &val));
1032:           if (val == defval) continue;

1034:           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1035:           for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart));
1036:           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1037:         }
1038:       }
1039:     }

1041:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1042:     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
1043:     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
1044:     PetscCall(PetscViewerASCIIPrintf(viewer, "\
1045: \\documentclass[tikz]{standalone}\n\n\
1046: \\usepackage{pgflibraryshapes}\n\
1047: \\usetikzlibrary{backgrounds}\n\
1048: \\usetikzlibrary{arrows}\n\
1049: \\begin{document}\n"));
1050:     if (size > 1) {
1051:       PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name));
1052:       for (p = 0; p < size; ++p) {
1053:         if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", "));
1054:         PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p));
1055:       }
1056:       PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n"));
1057:     }
1058:     if (drawHasse) {
1059:       PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart));

1061:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart));
1062:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1));
1063:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart));
1064:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.));
1065:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart));
1066:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1));
1067:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.));
1068:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart));
1069:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart));
1070:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1));
1071:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart));
1072:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.));
1073:     }
1074:     PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale));

1076:     /* Plot vertices */
1077:     PetscCall(VecGetArray(coordinates, &coords));
1078:     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
1079:     for (v = vStart; v < vEnd; ++v) {
1080:       PetscInt  off, dof, d;
1081:       PetscBool isLabeled = PETSC_FALSE;

1083:       if (wp && !PetscBTLookup(wp, v - pStart)) continue;
1084:       PetscCall(PetscSectionGetDof(coordSection, v, &dof));
1085:       PetscCall(PetscSectionGetOffset(coordSection, v, &off));
1086:       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1087:       PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof);
1088:       for (d = 0; d < dof; ++d) {
1089:         tcoords[d] = (double)(scale * PetscRealPart(coords[off + d]));
1090:         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1091:       }
1092:       /* Rotate coordinates since PGF makes z point out of the page instead of up */
1093:       if (dim == 3) {
1094:         PetscReal tmp = tcoords[1];
1095:         tcoords[1]    = tcoords[2];
1096:         tcoords[2]    = -tmp;
1097:       }
1098:       for (d = 0; d < dof; ++d) {
1099:         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1100:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1101:       }
1102:       if (drawHasse) color = colors[0 % numColors];
1103:       else color = colors[rank % numColors];
1104:       for (l = 0; l < numLabels; ++l) {
1105:         PetscInt val;
1106:         PetscCall(DMGetLabelValue(dm, names[l], v, &val));
1107:         if (val >= 0) {
1108:           color     = lcolors[l % numLColors];
1109:           isLabeled = PETSC_TRUE;
1110:           break;
1111:         }
1112:       }
1113:       if (drawNumbers[0]) {
1114:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v));
1115:       } else if (drawColors[0]) {
1116:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color));
1117:       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank));
1118:     }
1119:     PetscCall(VecRestoreArray(coordinates, &coords));
1120:     PetscCall(PetscViewerFlush(viewer));
1121:     /* Plot edges */
1122:     if (plotEdges) {
1123:       PetscCall(VecGetArray(coordinates, &coords));
1124:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n"));
1125:       for (e = eStart; e < eEnd; ++e) {
1126:         const PetscInt *cone;
1127:         PetscInt        coneSize, offA, offB, dof, d;

1129:         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1130:         PetscCall(DMPlexGetConeSize(dm, e, &coneSize));
1131:         PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize);
1132:         PetscCall(DMPlexGetCone(dm, e, &cone));
1133:         PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof));
1134:         PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA));
1135:         PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB));
1136:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "("));
1137:         for (d = 0; d < dof; ++d) {
1138:           tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d]));
1139:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1140:         }
1141:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1142:         if (dim == 3) {
1143:           PetscReal tmp = tcoords[1];
1144:           tcoords[1]    = tcoords[2];
1145:           tcoords[2]    = -tmp;
1146:         }
1147:         for (d = 0; d < dof; ++d) {
1148:           if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1149:           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]));
1150:         }
1151:         if (drawHasse) color = colors[1 % numColors];
1152:         else color = colors[rank % numColors];
1153:         for (l = 0; l < numLabels; ++l) {
1154:           PetscInt val;
1155:           PetscCall(DMGetLabelValue(dm, names[l], v, &val));
1156:           if (val >= 0) {
1157:             color = lcolors[l % numLColors];
1158:             break;
1159:           }
1160:         }
1161:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e));
1162:       }
1163:       PetscCall(VecRestoreArray(coordinates, &coords));
1164:       PetscCall(PetscViewerFlush(viewer));
1165:       PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n"));
1166:     }
1167:     /* Plot cells */
1168:     if (dim == 3 || !drawNumbers[1]) {
1169:       for (e = eStart; e < eEnd; ++e) {
1170:         const PetscInt *cone;

1172:         if (wp && !PetscBTLookup(wp, e - pStart)) continue;
1173:         color = colors[rank % numColors];
1174:         for (l = 0; l < numLabels; ++l) {
1175:           PetscInt val;
1176:           PetscCall(DMGetLabelValue(dm, names[l], e, &val));
1177:           if (val >= 0) {
1178:             color = lcolors[l % numLColors];
1179:             break;
1180:           }
1181:         }
1182:         PetscCall(DMPlexGetCone(dm, e, &cone));
1183:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank));
1184:       }
1185:     } else {
1186:       DMPolytopeType ct;

1188:       /* Drawing a 2D polygon */
1189:       for (c = cStart; c < cEnd; ++c) {
1190:         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1191:         PetscCall(DMPlexGetCellType(dm, c, &ct));
1192:         if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
1193:           const PetscInt *cone;
1194:           PetscInt        coneSize, e;

1196:           PetscCall(DMPlexGetCone(dm, c, &cone));
1197:           PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
1198:           for (e = 0; e < coneSize; ++e) {
1199:             const PetscInt *econe;

1201:             PetscCall(DMPlexGetCone(dm, cone[e], &econe));
1202:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank));
1203:           }
1204:         } else {
1205:           PetscInt *closure = NULL;
1206:           PetscInt  closureSize, Nv = 0, v;

1208:           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1209:           for (p = 0; p < closureSize * 2; p += 2) {
1210:             const PetscInt point = closure[p];

1212:             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1213:           }
1214:           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors]));
1215:           for (v = 0; v <= Nv; ++v) {
1216:             const PetscInt vertex = closure[v % Nv];

1218:             if (v > 0) {
1219:               if (plotEdges) {
1220:                 const PetscInt *edge;
1221:                 PetscInt        endpoints[2], ne;

1223:                 endpoints[0] = closure[v - 1];
1224:                 endpoints[1] = vertex;
1225:                 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge));
1226:                 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]);
1227:                 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank));
1228:                 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge));
1229:               } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- "));
1230:             }
1231:             PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank));
1232:           }
1233:           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n"));
1234:           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
1235:         }
1236:       }
1237:     }
1238:     for (c = cStart; c < cEnd; ++c) {
1239:       double             ccoords[3] = {0.0, 0.0, 0.0};
1240:       PetscBool          isLabeled  = PETSC_FALSE;
1241:       PetscScalar       *cellCoords = NULL;
1242:       const PetscScalar *array;
1243:       PetscInt           numCoords, cdim, d;
1244:       PetscBool          isDG;

1246:       if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1247:       PetscCall(DMGetCoordinateDim(dm, &cdim));
1248:       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1249:       PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords);
1250:       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path ("));
1251:       for (p = 0; p < numCoords / cdim; ++p) {
1252:         for (d = 0; d < cdim; ++d) {
1253:           tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d]));
1254:           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1255:         }
1256:         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1257:         if (cdim == 3) {
1258:           PetscReal tmp = tcoords[1];
1259:           tcoords[1]    = tcoords[2];
1260:           tcoords[2]    = -tmp;
1261:         }
1262:         for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d];
1263:       }
1264:       for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim);
1265:       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords));
1266:       for (d = 0; d < cdim; ++d) {
1267:         if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ","));
1268:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d]));
1269:       }
1270:       if (drawHasse) color = colors[depth % numColors];
1271:       else color = colors[rank % numColors];
1272:       for (l = 0; l < numLabels; ++l) {
1273:         PetscInt val;
1274:         PetscCall(DMGetLabelValue(dm, names[l], c, &val));
1275:         if (val >= 0) {
1276:           color     = lcolors[l % numLColors];
1277:           isLabeled = PETSC_TRUE;
1278:           break;
1279:         }
1280:       }
1281:       if (drawNumbers[dim]) {
1282:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c));
1283:       } else if (drawColors[dim]) {
1284:         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color));
1285:       } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank));
1286:     }
1287:     if (drawHasse) {
1288:       color = colors[depth % numColors];
1289:       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n"));
1290:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n"));
1291:       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1292:       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color));
1293:       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));

1295:       color = colors[1 % numColors];
1296:       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n"));
1297:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n"));
1298:       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1299:       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color));
1300:       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));

1302:       color = colors[0 % numColors];
1303:       PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n"));
1304:       PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n"));
1305:       PetscCall(PetscViewerASCIIPrintf(viewer, "{\n"));
1306:       PetscCall(PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color));
1307:       PetscCall(PetscViewerASCIIPrintf(viewer, "}\n"));

1309:       for (p = pStart; p < pEnd; ++p) {
1310:         const PetscInt *cone;
1311:         PetscInt        coneSize, cp;

1313:         PetscCall(DMPlexGetCone(dm, p, &cone));
1314:         PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
1315:         for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank));
1316:       }
1317:     }
1318:     PetscCall(PetscViewerFlush(viewer));
1319:     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
1320:     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n"));
1321:     PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n"));
1322:     for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l]));
1323:     for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c]));
1324:     for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c]));
1325:     PetscCall(PetscFree3(names, colors, lcolors));
1326:     PetscCall(PetscBTDestroy(&wp));
1327:   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
1328:     Vec                    cown, acown;
1329:     VecScatter             sct;
1330:     ISLocalToGlobalMapping g2l;
1331:     IS                     gid, acis;
1332:     MPI_Comm               comm, ncomm = MPI_COMM_NULL;
1333:     MPI_Group              ggroup, ngroup;
1334:     PetscScalar           *array, nid;
1335:     const PetscInt        *idxs;
1336:     PetscInt              *idxs2, *start, *adjacency, *work;
1337:     PetscInt64             lm[3], gm[3];
1338:     PetscInt               i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight;
1339:     PetscMPIInt            d1, d2, rank;

1341:     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1342:     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1343: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1344:     PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm));
1345: #endif
1346:     if (ncomm != MPI_COMM_NULL) {
1347:       PetscCallMPI(MPI_Comm_group(comm, &ggroup));
1348:       PetscCallMPI(MPI_Comm_group(ncomm, &ngroup));
1349:       d1 = 0;
1350:       PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2));
1351:       nid = d2;
1352:       PetscCallMPI(MPI_Group_free(&ggroup));
1353:       PetscCallMPI(MPI_Group_free(&ngroup));
1354:       PetscCallMPI(MPI_Comm_free(&ncomm));
1355:     } else nid = 0.0;

1357:     /* Get connectivity */
1358:     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1359:     PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid));

1361:     /* filter overlapped local cells */
1362:     PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
1363:     PetscCall(ISGetIndices(gid, &idxs));
1364:     PetscCall(ISGetLocalSize(gid, &cum));
1365:     PetscCall(PetscMalloc1(cum, &idxs2));
1366:     for (c = cStart, cum = 0; c < cEnd; c++) {
1367:       if (idxs[c - cStart] < 0) continue;
1368:       idxs2[cum++] = idxs[c - cStart];
1369:     }
1370:     PetscCall(ISRestoreIndices(gid, &idxs));
1371:     PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum);
1372:     PetscCall(ISDestroy(&gid));
1373:     PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid));

1375:     /* support for node-aware cell locality */
1376:     PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis));
1377:     PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown));
1378:     PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown));
1379:     PetscCall(VecGetArray(cown, &array));
1380:     for (c = 0; c < numVertices; c++) array[c] = nid;
1381:     PetscCall(VecRestoreArray(cown, &array));
1382:     PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct));
1383:     PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
1384:     PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD));
1385:     PetscCall(ISDestroy(&acis));
1386:     PetscCall(VecScatterDestroy(&sct));
1387:     PetscCall(VecDestroy(&cown));

1389:     /* compute edgeCut */
1390:     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]);
1391:     PetscCall(PetscMalloc1(cum, &work));
1392:     PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l));
1393:     PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH));
1394:     PetscCall(ISDestroy(&gid));
1395:     PetscCall(VecGetArray(acown, &array));
1396:     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1397:       PetscInt totl;

1399:       totl = start[c + 1] - start[c];
1400:       PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work));
1401:       for (i = 0; i < totl; i++) {
1402:         if (work[i] < 0) {
1403:           ect += 1;
1404:           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1405:         }
1406:       }
1407:     }
1408:     PetscCall(PetscFree(work));
1409:     PetscCall(VecRestoreArray(acown, &array));
1410:     lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT;
1411:     lm[1] = -numVertices;
1412:     PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm));
1413:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0]));
1414:     lm[0] = ect;                     /* edgeCut */
1415:     lm[1] = ectn;                    /* node-aware edgeCut */
1416:     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1417:     PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm));
1418:     PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2]));
1419: #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1420:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.));
1421: #else
1422:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0));
1423: #endif
1424:     PetscCall(ISLocalToGlobalMappingDestroy(&g2l));
1425:     PetscCall(PetscFree(start));
1426:     PetscCall(PetscFree(adjacency));
1427:     PetscCall(VecDestroy(&acown));
1428:   } else {
1429:     const char    *name;
1430:     PetscInt      *sizes, *hybsizes, *ghostsizes;
1431:     PetscInt       locDepth, depth, cellHeight, dim, d;
1432:     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1433:     PetscInt       numLabels, l, maxSize = 17;
1434:     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1435:     MPI_Comm       comm;
1436:     PetscMPIInt    size, rank;

1438:     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1439:     PetscCallMPI(MPI_Comm_size(comm, &size));
1440:     PetscCallMPI(MPI_Comm_rank(comm, &rank));
1441:     PetscCall(DMGetDimension(dm, &dim));
1442:     PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
1443:     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
1444:     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s"));
1445:     else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s"));
1446:     if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, "  Cells are at height %" PetscInt_FMT "\n", cellHeight));
1447:     PetscCall(DMPlexGetDepth(dm, &locDepth));
1448:     PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
1449:     PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd));
1450:     gcNum = gcEnd - gcStart;
1451:     if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes));
1452:     else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes));
1453:     for (d = 0; d <= depth; d++) {
1454:       PetscInt Nc[2] = {0, 0}, ict;

1456:       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
1457:       if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0));
1458:       ict = ct0;
1459:       PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm));
1460:       ct0 = (DMPolytopeType)ict;
1461:       for (p = pStart; p < pEnd; ++p) {
1462:         DMPolytopeType ct;

1464:         PetscCall(DMPlexGetCellType(dm, p, &ct));
1465:         if (ct == ct0) ++Nc[0];
1466:         else ++Nc[1];
1467:       }
1468:       if (size < maxSize) {
1469:         PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm));
1470:         PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm));
1471:         if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm));
1472:         PetscCall(PetscViewerASCIIPrintf(viewer, "  Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1473:         for (p = 0; p < size; ++p) {
1474:           if (rank == 0) {
1475:             PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p]));
1476:             if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p]));
1477:             if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p]));
1478:           }
1479:         }
1480:       } else {
1481:         PetscInt locMinMax[2];

1483:         locMinMax[0] = Nc[0] + Nc[1];
1484:         locMinMax[1] = Nc[0] + Nc[1];
1485:         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes));
1486:         locMinMax[0] = Nc[1];
1487:         locMinMax[1] = Nc[1];
1488:         PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes));
1489:         if (d == depth) {
1490:           locMinMax[0] = gcNum;
1491:           locMinMax[1] = gcNum;
1492:           PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes));
1493:         }
1494:         PetscCall(PetscViewerASCIIPrintf(viewer, "  Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d));
1495:         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]));
1496:         if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]));
1497:         if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]));
1498:       }
1499:       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1500:     }
1501:     PetscCall(PetscFree3(sizes, hybsizes, ghostsizes));
1502:     {
1503:       const PetscReal *maxCell;
1504:       const PetscReal *L;
1505:       PetscBool        localized;

1507:       PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L));
1508:       PetscCall(DMGetCoordinatesLocalized(dm, &localized));
1509:       if (L || localized) {
1510:         PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh"));
1511:         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1512:         if (L) {
1513:           PetscCall(PetscViewerASCIIPrintf(viewer, " ("));
1514:           for (d = 0; d < dim; ++d) {
1515:             if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
1516:             PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE"));
1517:           }
1518:           PetscCall(PetscViewerASCIIPrintf(viewer, ")"));
1519:         }
1520:         PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized"));
1521:         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1522:       }
1523:     }
1524:     PetscCall(DMGetNumLabels(dm, &numLabels));
1525:     if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n"));
1526:     for (l = 0; l < numLabels; ++l) {
1527:       DMLabel         label;
1528:       const char     *name;
1529:       IS              valueIS;
1530:       const PetscInt *values;
1531:       PetscInt        numValues, v;

1533:       PetscCall(DMGetLabelName(dm, l, &name));
1534:       PetscCall(DMGetLabel(dm, name, &label));
1535:       PetscCall(DMLabelGetNumValues(label, &numValues));
1536:       PetscCall(PetscViewerASCIIPrintf(viewer, "  %s: %" PetscInt_FMT " strata with value/size (", name, numValues));
1537:       PetscCall(DMLabelGetValueIS(label, &valueIS));
1538:       PetscCall(ISGetIndices(valueIS, &values));
1539:       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1540:       for (v = 0; v < numValues; ++v) {
1541:         PetscInt size;

1543:         PetscCall(DMLabelGetStratumSize(label, values[v], &size));
1544:         if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
1545:         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size));
1546:       }
1547:       PetscCall(PetscViewerASCIIPrintf(viewer, ")\n"));
1548:       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1549:       PetscCall(ISRestoreIndices(valueIS, &values));
1550:       PetscCall(ISDestroy(&valueIS));
1551:     }
1552:     {
1553:       char    **labelNames;
1554:       PetscInt  Nl = numLabels;
1555:       PetscBool flg;

1557:       PetscCall(PetscMalloc1(Nl, &labelNames));
1558:       PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg));
1559:       for (l = 0; l < Nl; ++l) {
1560:         DMLabel label;

1562:         PetscCall(DMHasLabel(dm, labelNames[l], &flg));
1563:         if (flg) {
1564:           PetscCall(DMGetLabel(dm, labelNames[l], &label));
1565:           PetscCall(DMLabelView(label, viewer));
1566:         }
1567:         PetscCall(PetscFree(labelNames[l]));
1568:       }
1569:       PetscCall(PetscFree(labelNames));
1570:     }
1571:     /* If no fields are specified, people do not want to see adjacency */
1572:     if (dm->Nf) {
1573:       PetscInt f;

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

1578:         PetscCall(PetscObjectGetName(dm->fields[f].disc, &name));
1579:         if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name));
1580:         PetscCall(PetscViewerASCIIPushTab(viewer));
1581:         if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer));
1582:         if (dm->fields[f].adjacency[0]) {
1583:           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n"));
1584:           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n"));
1585:         } else {
1586:           if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n"));
1587:           else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n"));
1588:         }
1589:         PetscCall(PetscViewerASCIIPopTab(viewer));
1590:       }
1591:     }
1592:     PetscCall(DMGetCoarseDM(dm, &cdm));
1593:     if (cdm) {
1594:       PetscCall(PetscViewerASCIIPushTab(viewer));
1595:       PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n"));
1596:       PetscCall(DMPlexView_Ascii(cdm, viewer));
1597:       PetscCall(PetscViewerASCIIPopTab(viewer));
1598:     }
1599:   }
1600:   PetscFunctionReturn(PETSC_SUCCESS);
1601: }

1603: static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1604: {
1605:   DMPolytopeType ct;
1606:   PetscMPIInt    rank;
1607:   PetscInt       cdim;

1609:   PetscFunctionBegin;
1610:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1611:   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1612:   PetscCall(DMGetCoordinateDim(dm, &cdim));
1613:   switch (ct) {
1614:   case DM_POLYTOPE_SEGMENT:
1615:   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1616:     switch (cdim) {
1617:     case 1: {
1618:       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1619:       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */

1621:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK));
1622:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK));
1623:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK));
1624:     } break;
1625:     case 2: {
1626:       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1627:       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1628:       const PetscReal l  = 0.1 / PetscSqrtReal(dx * dx + dy * dy);

1630:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1631:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK));
1632:       PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK));
1633:     } break;
1634:     default:
1635:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim);
1636:     }
1637:     break;
1638:   case DM_POLYTOPE_TRIANGLE:
1639:     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
1640:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1641:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1642:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1643:     break;
1644:   case DM_POLYTOPE_QUADRILATERAL:
1645:     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
1646:     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
1647:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1648:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1649:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
1650:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1651:     break;
1652:   case DM_POLYTOPE_SEG_PRISM_TENSOR:
1653:     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
1654:     PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2));
1655:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK));
1656:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK));
1657:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK));
1658:     PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK));
1659:     break;
1660:   case DM_POLYTOPE_FV_GHOST:
1661:     break;
1662:   default:
1663:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1664:   }
1665:   PetscFunctionReturn(PETSC_SUCCESS);
1666: }

1668: static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1669: {
1670:   DMPolytopeType ct;
1671:   PetscReal      centroid[2] = {0., 0.};
1672:   PetscMPIInt    rank;
1673:   PetscInt       fillColor, v, e, d;

1675:   PetscFunctionBegin;
1676:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1677:   PetscCall(DMPlexGetCellType(dm, cell, &ct));
1678:   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2;
1679:   switch (ct) {
1680:   case DM_POLYTOPE_TRIANGLE: {
1681:     PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};

1683:     for (v = 0; v < 3; ++v) {
1684:       centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.;
1685:       centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.;
1686:     }
1687:     for (e = 0; e < 3; ++e) {
1688:       refCoords[0] = refVertices[e * 2 + 0];
1689:       refCoords[1] = refVertices[e * 2 + 1];
1690:       for (d = 1; d <= edgeDiv; ++d) {
1691:         refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv;
1692:         refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv;
1693:       }
1694:       PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords));
1695:       for (d = 0; d < edgeDiv; ++d) {
1696:         PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor));
1697:         PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK));
1698:       }
1699:     }
1700:   } break;
1701:   default:
1702:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1703:   }
1704:   PetscFunctionReturn(PETSC_SUCCESS);
1705: }

1707: static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1708: {
1709:   PetscDraw    draw;
1710:   DM           cdm;
1711:   PetscSection coordSection;
1712:   Vec          coordinates;
1713:   PetscReal    xyl[3], xyr[3];
1714:   PetscReal   *refCoords, *edgeCoords;
1715:   PetscBool    isnull, drawAffine = PETSC_TRUE;
1716:   PetscInt     dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4;

1718:   PetscFunctionBegin;
1719:   PetscCall(DMGetCoordinateDim(dm, &dim));
1720:   PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim);
1721:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL));
1722:   if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords));
1723:   PetscCall(DMGetCoordinateDM(dm, &cdm));
1724:   PetscCall(DMGetLocalSection(cdm, &coordSection));
1725:   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
1726:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1727:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));

1729:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1730:   PetscCall(PetscDrawIsNull(draw, &isnull));
1731:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
1732:   PetscCall(PetscDrawSetTitle(draw, "Mesh"));

1734:   PetscCall(DMGetBoundingBox(dm, xyl, xyr));
1735:   PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]));
1736:   PetscCall(PetscDrawClear(draw));

1738:   for (c = cStart; c < cEnd; ++c) {
1739:     PetscScalar       *coords = NULL;
1740:     const PetscScalar *coords_arr;
1741:     PetscInt           numCoords;
1742:     PetscBool          isDG;

1744:     PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1745:     if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords));
1746:     else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords));
1747:     PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords));
1748:   }
1749:   if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords));
1750:   PetscCall(PetscDrawFlush(draw));
1751:   PetscCall(PetscDrawPause(draw));
1752:   PetscCall(PetscDrawSave(draw));
1753:   PetscFunctionReturn(PETSC_SUCCESS);
1754: }

1756: #if defined(PETSC_HAVE_EXODUSII)
1757:   #include <exodusII.h>
1758: #include <petscviewerexodusii.h>
1759: #endif

1761: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1762: {
1763:   PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns;
1764:   char      name[PETSC_MAX_PATH_LEN];

1766:   PetscFunctionBegin;
1769:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1770:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
1771:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1772:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
1773:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
1774:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus));
1775:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns));
1776:   if (iascii) {
1777:     PetscViewerFormat format;
1778:     PetscCall(PetscViewerGetFormat(viewer, &format));
1779:     if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer));
1780:     else PetscCall(DMPlexView_Ascii(dm, viewer));
1781:   } else if (ishdf5) {
1782: #if defined(PETSC_HAVE_HDF5)
1783:     PetscCall(DMPlexView_HDF5_Internal(dm, viewer));
1784: #else
1785:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1786: #endif
1787:   } else if (isvtk) {
1788:     PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer));
1789:   } else if (isdraw) {
1790:     PetscCall(DMPlexView_Draw(dm, viewer));
1791:   } else if (isglvis) {
1792:     PetscCall(DMPlexView_GLVis(dm, viewer));
1793: #if defined(PETSC_HAVE_EXODUSII)
1794:   } else if (isexodus) {
1795:     /*
1796:       exodusII requires that all sets be part of exactly one cell set.
1797:       If the dm does not have a "Cell Sets" label defined, we create one
1798:       with ID 1, containing all cells.
1799:       Note that if the Cell Sets label is defined but does not cover all cells,
1800:       we may still have a problem. This should probably be checked here or in the viewer;
1801:     */
1802:     PetscInt numCS;
1803:     PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS));
1804:     if (!numCS) {
1805:       PetscInt cStart, cEnd, c;
1806:       PetscCall(DMCreateLabel(dm, "Cell Sets"));
1807:       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1808:       for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1));
1809:     }
1810:     PetscCall(DMView_PlexExodusII(dm, viewer));
1811: #endif
1812: #if defined(PETSC_HAVE_CGNS)
1813:   } else if (iscgns) {
1814:     PetscCall(DMView_PlexCGNS(dm, viewer));
1815: #endif
1816:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1817:   /* Optionally view the partition */
1818:   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg));
1819:   if (flg) {
1820:     Vec ranks;
1821:     PetscCall(DMPlexCreateRankField(dm, &ranks));
1822:     PetscCall(VecView(ranks, viewer));
1823:     PetscCall(VecDestroy(&ranks));
1824:   }
1825:   /* Optionally view a label */
1826:   PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg));
1827:   if (flg) {
1828:     DMLabel label;
1829:     Vec     val;

1831:     PetscCall(DMGetLabel(dm, name, &label));
1832:     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1833:     PetscCall(DMPlexCreateLabelField(dm, label, &val));
1834:     PetscCall(VecView(val, viewer));
1835:     PetscCall(VecDestroy(&val));
1836:   }
1837:   PetscFunctionReturn(PETSC_SUCCESS);
1838: }

1840: /*@
1841:   DMPlexTopologyView - Saves a `DMPLEX` topology into a file

1843:   Collective

1845:   Input Parameters:
1846: + dm     - The `DM` whose topology is to be saved
1847: - viewer - The `PetscViewer` to save it in

1849:   Level: advanced

1851: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer`
1852: @*/
1853: PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
1854: {
1855:   PetscBool ishdf5;

1857:   PetscFunctionBegin;
1860:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1861:   PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0));
1862:   if (ishdf5) {
1863: #if defined(PETSC_HAVE_HDF5)
1864:     PetscViewerFormat format;
1865:     PetscCall(PetscViewerGetFormat(viewer, &format));
1866:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1867:       IS globalPointNumbering;

1869:       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
1870:       PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer));
1871:       PetscCall(ISDestroy(&globalPointNumbering));
1872:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
1873: #else
1874:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1875: #endif
1876:   }
1877:   PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0));
1878:   PetscFunctionReturn(PETSC_SUCCESS);
1879: }

1881: /*@
1882:   DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file

1884:   Collective

1886:   Input Parameters:
1887: + dm     - The `DM` whose coordinates are to be saved
1888: - viewer - The `PetscViewer` for saving

1890:   Level: advanced

1892: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer`
1893: @*/
1894: PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
1895: {
1896:   PetscBool ishdf5;

1898:   PetscFunctionBegin;
1901:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1902:   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
1903:   if (ishdf5) {
1904: #if defined(PETSC_HAVE_HDF5)
1905:     PetscViewerFormat format;
1906:     PetscCall(PetscViewerGetFormat(viewer, &format));
1907:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1908:       PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer));
1909:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
1910: #else
1911:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1912: #endif
1913:   }
1914:   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0));
1915:   PetscFunctionReturn(PETSC_SUCCESS);
1916: }

1918: /*@
1919:   DMPlexLabelsView - Saves `DMPLEX` labels into a file

1921:   Collective

1923:   Input Parameters:
1924: + dm     - The `DM` whose labels are to be saved
1925: - viewer - The `PetscViewer` for saving

1927:   Level: advanced

1929: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer`
1930: @*/
1931: PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1932: {
1933:   PetscBool ishdf5;

1935:   PetscFunctionBegin;
1938:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1939:   PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0));
1940:   if (ishdf5) {
1941: #if defined(PETSC_HAVE_HDF5)
1942:     IS                globalPointNumbering;
1943:     PetscViewerFormat format;

1945:     PetscCall(PetscViewerGetFormat(viewer, &format));
1946:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1947:       PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering));
1948:       PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer));
1949:       PetscCall(ISDestroy(&globalPointNumbering));
1950:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1951: #else
1952:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1953: #endif
1954:   }
1955:   PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0));
1956:   PetscFunctionReturn(PETSC_SUCCESS);
1957: }

1959: /*@
1960:   DMPlexSectionView - Saves a section associated with a `DMPLEX`

1962:   Collective

1964:   Input Parameters:
1965: + dm        - The `DM` that contains the topology on which the section to be saved is defined
1966: . viewer    - The `PetscViewer` for saving
1967: - sectiondm - The `DM` that contains the section to be saved

1969:   Level: advanced

1971:   Notes:
1972:   This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points.

1974:   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.

1976: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer`
1977: @*/
1978: PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1979: {
1980:   PetscBool ishdf5;

1982:   PetscFunctionBegin;
1986:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
1987:   PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0));
1988:   if (ishdf5) {
1989: #if defined(PETSC_HAVE_HDF5)
1990:     PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm));
1991: #else
1992:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1993: #endif
1994:   }
1995:   PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0));
1996:   PetscFunctionReturn(PETSC_SUCCESS);
1997: }

1999: /*@
2000:   DMPlexGlobalVectorView - Saves a global vector

2002:   Collective

2004:   Input Parameters:
2005: + dm        - The `DM` that represents the topology
2006: . viewer    - The `PetscViewer` to save data with
2007: . sectiondm - The `DM` that contains the global section on which vec is defined
2008: - vec       - The global vector to be saved

2010:   Level: advanced

2012:   Notes:
2013:   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.

2015:   Calling sequence:
2016: .vb
2017:        DMCreate(PETSC_COMM_WORLD, &dm);
2018:        DMSetType(dm, DMPLEX);
2019:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2020:        DMClone(dm, &sectiondm);
2021:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2022:        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2023:        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2024:        PetscSectionSetChart(section, pStart, pEnd);
2025:        PetscSectionSetUp(section);
2026:        DMSetLocalSection(sectiondm, section);
2027:        PetscSectionDestroy(&section);
2028:        DMGetGlobalVector(sectiondm, &vec);
2029:        PetscObjectSetName((PetscObject)vec, "vec_name");
2030:        DMPlexTopologyView(dm, viewer);
2031:        DMPlexSectionView(dm, viewer, sectiondm);
2032:        DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
2033:        DMRestoreGlobalVector(sectiondm, &vec);
2034:        DMDestroy(&sectiondm);
2035:        DMDestroy(&dm);
2036: .ve

2038: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
2039: @*/
2040: PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2041: {
2042:   PetscBool ishdf5;

2044:   PetscFunctionBegin;
2049:   /* Check consistency */
2050:   {
2051:     PetscSection section;
2052:     PetscBool    includesConstraints;
2053:     PetscInt     m, m1;

2055:     PetscCall(VecGetLocalSize(vec, &m1));
2056:     PetscCall(DMGetGlobalSection(sectiondm, &section));
2057:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2058:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2059:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2060:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
2061:   }
2062:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2063:   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
2064:   if (ishdf5) {
2065: #if defined(PETSC_HAVE_HDF5)
2066:     PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
2067: #else
2068:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2069: #endif
2070:   }
2071:   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0));
2072:   PetscFunctionReturn(PETSC_SUCCESS);
2073: }

2075: /*@
2076:   DMPlexLocalVectorView - Saves a local vector

2078:   Collective

2080:   Input Parameters:
2081: + dm        - The `DM` that represents the topology
2082: . viewer    - The `PetscViewer` to save data with
2083: . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm`
2084: - vec       - The local vector to be saved

2086:   Level: advanced

2088:   Note:
2089:   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.

2091:   Calling sequence:
2092: .vb
2093:        DMCreate(PETSC_COMM_WORLD, &dm);
2094:        DMSetType(dm, DMPLEX);
2095:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2096:        DMClone(dm, &sectiondm);
2097:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2098:        PetscSectionCreate(PETSC_COMM_WORLD, &section);
2099:        DMPlexGetChart(sectiondm, &pStart, &pEnd);
2100:        PetscSectionSetChart(section, pStart, pEnd);
2101:        PetscSectionSetUp(section);
2102:        DMSetLocalSection(sectiondm, section);
2103:        DMGetLocalVector(sectiondm, &vec);
2104:        PetscObjectSetName((PetscObject)vec, "vec_name");
2105:        DMPlexTopologyView(dm, viewer);
2106:        DMPlexSectionView(dm, viewer, sectiondm);
2107:        DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
2108:        DMRestoreLocalVector(sectiondm, &vec);
2109:        DMDestroy(&sectiondm);
2110:        DMDestroy(&dm);
2111: .ve

2113: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`
2114: @*/
2115: PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
2116: {
2117:   PetscBool ishdf5;

2119:   PetscFunctionBegin;
2124:   /* Check consistency */
2125:   {
2126:     PetscSection section;
2127:     PetscBool    includesConstraints;
2128:     PetscInt     m, m1;

2130:     PetscCall(VecGetLocalSize(vec, &m1));
2131:     PetscCall(DMGetLocalSection(sectiondm, &section));
2132:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2133:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2134:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2135:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
2136:   }
2137:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2138:   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
2139:   if (ishdf5) {
2140: #if defined(PETSC_HAVE_HDF5)
2141:     PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec));
2142: #else
2143:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2144: #endif
2145:   }
2146:   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0));
2147:   PetscFunctionReturn(PETSC_SUCCESS);
2148: }

2150: PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
2151: {
2152:   PetscBool ishdf5;

2154:   PetscFunctionBegin;
2157:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2158:   if (ishdf5) {
2159: #if defined(PETSC_HAVE_HDF5)
2160:     PetscViewerFormat format;
2161:     PetscCall(PetscViewerGetFormat(viewer, &format));
2162:     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
2163:       PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer));
2164:     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2165:       PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer));
2166:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2167:     PetscFunctionReturn(PETSC_SUCCESS);
2168: #else
2169:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2170: #endif
2171:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2172: }

2174: /*@
2175:   DMPlexTopologyLoad - Loads a topology into a `DMPLEX`

2177:   Collective

2179:   Input Parameters:
2180: + dm     - The `DM` into which the topology is loaded
2181: - viewer - The `PetscViewer` for the saved topology

2183:   Output Parameter:
2184: . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded

2186:   Level: advanced

2188: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2189:           `PetscViewer`, `PetscSF`
2190: @*/
2191: PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2192: {
2193:   PetscBool ishdf5;

2195:   PetscFunctionBegin;
2198:   if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3);
2199:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2200:   PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2201:   if (ishdf5) {
2202: #if defined(PETSC_HAVE_HDF5)
2203:     PetscViewerFormat format;
2204:     PetscCall(PetscViewerGetFormat(viewer, &format));
2205:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2206:       PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2207:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2208: #else
2209:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2210: #endif
2211:   }
2212:   PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0));
2213:   PetscFunctionReturn(PETSC_SUCCESS);
2214: }

2216: /*@
2217:   DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX`

2219:   Collective

2221:   Input Parameters:
2222: + dm                   - The `DM` into which the coordinates are loaded
2223: . viewer               - The `PetscViewer` for the saved coordinates
2224: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer

2226:   Level: advanced

2228: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2229:           `PetscSF`, `PetscViewer`
2230: @*/
2231: PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2232: {
2233:   PetscBool ishdf5;

2235:   PetscFunctionBegin;
2239:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2240:   PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
2241:   if (ishdf5) {
2242: #if defined(PETSC_HAVE_HDF5)
2243:     PetscViewerFormat format;
2244:     PetscCall(PetscViewerGetFormat(viewer, &format));
2245:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2246:       PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2247:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2248: #else
2249:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2250: #endif
2251:   }
2252:   PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0));
2253:   PetscFunctionReturn(PETSC_SUCCESS);
2254: }

2256: /*@
2257:   DMPlexLabelsLoad - Loads labels into a `DMPLEX`

2259:   Collective

2261:   Input Parameters:
2262: + dm                   - The `DM` into which the labels are loaded
2263: . viewer               - The `PetscViewer` for the saved labels
2264: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer

2266:   Level: advanced

2268:   Note:
2269:   The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs.

2271: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`,
2272:           `PetscSF`, `PetscViewer`
2273: @*/
2274: PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2275: {
2276:   PetscBool ishdf5;

2278:   PetscFunctionBegin;
2282:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2283:   PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2284:   if (ishdf5) {
2285: #if defined(PETSC_HAVE_HDF5)
2286:     PetscViewerFormat format;

2288:     PetscCall(PetscViewerGetFormat(viewer, &format));
2289:     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2290:       PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF));
2291:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2292: #else
2293:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2294: #endif
2295:   }
2296:   PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0));
2297:   PetscFunctionReturn(PETSC_SUCCESS);
2298: }

2300: /*@
2301:   DMPlexSectionLoad - Loads section into a `DMPLEX`

2303:   Collective

2305:   Input Parameters:
2306: + dm                   - The `DM` that represents the topology
2307: . viewer               - The `PetscViewer` that represents the on-disk section (sectionA)
2308: . sectiondm            - The `DM` into which the on-disk section (sectionA) is migrated
2309: - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer

2311:   Output Parameters:
2312: + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed)
2313: - localDofSF  - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed)

2315:   Level: advanced

2317:   Notes:
2318:   This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points.

2320:   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.

2322:   The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section.

2324:   Example using 2 processes:
2325: .vb
2326:   NX (number of points on dm): 4
2327:   sectionA                   : the on-disk section
2328:   vecA                       : a vector associated with sectionA
2329:   sectionB                   : sectiondm's local section constructed in this function
2330:   vecB (local)               : a vector associated with sectiondm's local section
2331:   vecB (global)              : a vector associated with sectiondm's global section

2333:                                      rank 0    rank 1
2334:   vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2335:   sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2336:   sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2337:   sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2338:   [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2339:   sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2340:   sectionB->atlasDof             :     1 0 1 | 1 3
2341:   sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2342:   vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2343:   vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2344: .ve
2345:   where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.

2347: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer`
2348: @*/
2349: PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2350: {
2351:   PetscBool ishdf5;

2353:   PetscFunctionBegin;
2358:   if (globalDofSF) PetscAssertPointer(globalDofSF, 5);
2359:   if (localDofSF) PetscAssertPointer(localDofSF, 6);
2360:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2361:   PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2362:   if (ishdf5) {
2363: #if defined(PETSC_HAVE_HDF5)
2364:     PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF));
2365: #else
2366:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2367: #endif
2368:   }
2369:   PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0));
2370:   PetscFunctionReturn(PETSC_SUCCESS);
2371: }

2373: /*@
2374:   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector

2376:   Collective

2378:   Input Parameters:
2379: + dm        - The `DM` that represents the topology
2380: . viewer    - The `PetscViewer` that represents the on-disk vector data
2381: . sectiondm - The `DM` that contains the global section on which vec is defined
2382: . sf        - The `PetscSF` that migrates the on-disk vector data into vec
2383: - vec       - The global vector to set values of

2385:   Level: advanced

2387:   Notes:
2388:   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.

2390:   Calling sequence:
2391: .vb
2392:        DMCreate(PETSC_COMM_WORLD, &dm);
2393:        DMSetType(dm, DMPLEX);
2394:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2395:        DMPlexTopologyLoad(dm, viewer, &sfX);
2396:        DMClone(dm, &sectiondm);
2397:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2398:        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2399:        DMGetGlobalVector(sectiondm, &vec);
2400:        PetscObjectSetName((PetscObject)vec, "vec_name");
2401:        DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2402:        DMRestoreGlobalVector(sectiondm, &vec);
2403:        PetscSFDestroy(&gsf);
2404:        PetscSFDestroy(&sfX);
2405:        DMDestroy(&sectiondm);
2406:        DMDestroy(&dm);
2407: .ve

2409: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2410:           `PetscSF`, `PetscViewer`
2411: @*/
2412: PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2413: {
2414:   PetscBool ishdf5;

2416:   PetscFunctionBegin;
2422:   /* Check consistency */
2423:   {
2424:     PetscSection section;
2425:     PetscBool    includesConstraints;
2426:     PetscInt     m, m1;

2428:     PetscCall(VecGetLocalSize(vec, &m1));
2429:     PetscCall(DMGetGlobalSection(sectiondm, &section));
2430:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2431:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2432:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2433:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m);
2434:   }
2435:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2436:   PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
2437:   if (ishdf5) {
2438: #if defined(PETSC_HAVE_HDF5)
2439:     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2440: #else
2441:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2442: #endif
2443:   }
2444:   PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0));
2445:   PetscFunctionReturn(PETSC_SUCCESS);
2446: }

2448: /*@
2449:   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector

2451:   Collective

2453:   Input Parameters:
2454: + dm        - The `DM` that represents the topology
2455: . viewer    - The `PetscViewer` that represents the on-disk vector data
2456: . sectiondm - The `DM` that contains the local section on which vec is defined
2457: . sf        - The `PetscSF` that migrates the on-disk vector data into vec
2458: - vec       - The local vector to set values of

2460:   Level: advanced

2462:   Notes:
2463:   In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.

2465:   Calling sequence:
2466: .vb
2467:        DMCreate(PETSC_COMM_WORLD, &dm);
2468:        DMSetType(dm, DMPLEX);
2469:        PetscObjectSetName((PetscObject)dm, "topologydm_name");
2470:        DMPlexTopologyLoad(dm, viewer, &sfX);
2471:        DMClone(dm, &sectiondm);
2472:        PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2473:        DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2474:        DMGetLocalVector(sectiondm, &vec);
2475:        PetscObjectSetName((PetscObject)vec, "vec_name");
2476:        DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2477:        DMRestoreLocalVector(sectiondm, &vec);
2478:        PetscSFDestroy(&lsf);
2479:        PetscSFDestroy(&sfX);
2480:        DMDestroy(&sectiondm);
2481:        DMDestroy(&dm);
2482: .ve

2484: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`,
2485:           `PetscSF`, `PetscViewer`
2486: @*/
2487: PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2488: {
2489:   PetscBool ishdf5;

2491:   PetscFunctionBegin;
2497:   /* Check consistency */
2498:   {
2499:     PetscSection section;
2500:     PetscBool    includesConstraints;
2501:     PetscInt     m, m1;

2503:     PetscCall(VecGetLocalSize(vec, &m1));
2504:     PetscCall(DMGetLocalSection(sectiondm, &section));
2505:     PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints));
2506:     if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m));
2507:     else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m));
2508:     PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m);
2509:   }
2510:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2511:   PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
2512:   if (ishdf5) {
2513: #if defined(PETSC_HAVE_HDF5)
2514:     PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec));
2515: #else
2516:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2517: #endif
2518:   }
2519:   PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0));
2520:   PetscFunctionReturn(PETSC_SUCCESS);
2521: }

2523: PetscErrorCode DMDestroy_Plex(DM dm)
2524: {
2525:   DM_Plex *mesh = (DM_Plex *)dm->data;

2527:   PetscFunctionBegin;
2528:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
2529:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL));
2530:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
2531:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL));
2532:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL));
2533:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2534:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL));
2535:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL));
2536:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
2537:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL));
2538:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL));
2539:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
2540:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL));
2541:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL));
2542:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL));
2543:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL));
2544:   if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
2545:   PetscCall(PetscSectionDestroy(&mesh->coneSection));
2546:   PetscCall(PetscFree(mesh->cones));
2547:   PetscCall(PetscFree(mesh->coneOrientations));
2548:   PetscCall(PetscSectionDestroy(&mesh->supportSection));
2549:   PetscCall(PetscSectionDestroy(&mesh->subdomainSection));
2550:   PetscCall(PetscFree(mesh->supports));
2551:   PetscCall(PetscFree(mesh->cellTypes));
2552:   PetscCall(DMPlexTransformDestroy(&mesh->tr));
2553:   PetscCall(PetscFree(mesh->tetgenOpts));
2554:   PetscCall(PetscFree(mesh->triangleOpts));
2555:   PetscCall(PetscFree(mesh->transformType));
2556:   PetscCall(PetscFree(mesh->distributionName));
2557:   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
2558:   PetscCall(DMLabelDestroy(&mesh->subpointMap));
2559:   PetscCall(ISDestroy(&mesh->subpointIS));
2560:   PetscCall(ISDestroy(&mesh->globalVertexNumbers));
2561:   PetscCall(ISDestroy(&mesh->globalCellNumbers));
2562:   PetscCall(PetscSFDestroy(&mesh->periodic.face_sf));
2563:   PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf));
2564:   PetscCall(ISDestroy(&mesh->periodic.periodic_points));
2565:   PetscCall(PetscSectionDestroy(&mesh->anchorSection));
2566:   PetscCall(ISDestroy(&mesh->anchorIS));
2567:   PetscCall(PetscSectionDestroy(&mesh->parentSection));
2568:   PetscCall(PetscFree(mesh->parents));
2569:   PetscCall(PetscFree(mesh->childIDs));
2570:   PetscCall(PetscSectionDestroy(&mesh->childSection));
2571:   PetscCall(PetscFree(mesh->children));
2572:   PetscCall(DMDestroy(&mesh->referenceTree));
2573:   PetscCall(PetscGridHashDestroy(&mesh->lbox));
2574:   PetscCall(PetscFree(mesh->neighbors));
2575:   if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx));
2576:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
2577:   PetscCall(PetscFree(mesh));
2578:   PetscFunctionReturn(PETSC_SUCCESS);
2579: }

2581: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2582: {
2583:   PetscSection           sectionGlobal;
2584:   PetscInt               bs = -1, mbs;
2585:   PetscInt               localSize, localStart = 0;
2586:   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2587:   MatType                mtype;
2588:   ISLocalToGlobalMapping ltog;

2590:   PetscFunctionBegin;
2591:   PetscCall(MatInitializePackage());
2592:   mtype = dm->mattype;
2593:   PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
2594:   /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */
2595:   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize));
2596:   PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
2597:   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
2598:   PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE));
2599:   PetscCall(MatSetType(*J, mtype));
2600:   PetscCall(MatSetFromOptions(*J));
2601:   PetscCall(MatGetBlockSize(*J, &mbs));
2602:   if (mbs > 1) bs = mbs;
2603:   PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell));
2604:   PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock));
2605:   PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock));
2606:   PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock));
2607:   PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock));
2608:   PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock));
2609:   PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock));
2610:   PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS));
2611:   if (!isShell) {
2612:     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2613:     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks;
2614:     PetscInt  pStart, pEnd, p, dof, cdof, num_fields;

2616:     PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));

2618:     PetscCall(PetscCalloc1(localSize, &pblocks));
2619:     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
2620:     PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields));
2621:     for (p = pStart; p < pEnd; ++p) {
2622:       switch (dm->blocking_type) {
2623:       case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point
2624:         PetscInt bdof, offset;

2626:         PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof));
2627:         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset));
2628:         PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof));
2629:         for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof;
2630:         dof  = dof < 0 ? -(dof + 1) : dof;
2631:         bdof = cdof && (dof - cdof) ? 1 : dof;
2632:         if (dof) {
2633:           if (bs < 0) {
2634:             bs = bdof;
2635:           } else if (bs != bdof) {
2636:             bs = 1;
2637:           }
2638:         }
2639:       } break;
2640:       case DM_BLOCKING_FIELD_NODE: {
2641:         for (PetscInt field = 0; field < num_fields; field++) {
2642:           PetscInt num_comp, bdof, offset;
2643:           PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp));
2644:           PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof));
2645:           if (dof < 0) continue;
2646:           PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset));
2647:           PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof));
2648:           PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp);
2649:           PetscInt num_nodes = dof / num_comp;
2650:           for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes;
2651:           // Handle possibly constant block size (unlikely)
2652:           bdof = cdof && (dof - cdof) ? 1 : dof;
2653:           if (dof) {
2654:             if (bs < 0) {
2655:               bs = bdof;
2656:             } else if (bs != bdof) {
2657:               bs = 1;
2658:             }
2659:           }
2660:         }
2661:       } break;
2662:       }
2663:     }
2664:     /* Must have same blocksize on all procs (some might have no points) */
2665:     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2666:     bsLocal[1] = bs;
2667:     PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
2668:     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2669:     else bs = bsMinMax[0];
2670:     bs = PetscMax(1, bs);
2671:     PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
2672:     if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters
2673:       PetscCall(MatSetBlockSize(*J, bs));
2674:       PetscCall(MatSetUp(*J));
2675:     } else {
2676:       PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu));
2677:       PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix));
2678:       PetscCall(PetscFree4(dnz, onz, dnzu, onzu));
2679:     }
2680:     { // Consolidate blocks
2681:       PetscInt nblocks = 0;
2682:       for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) {
2683:         if (pblocks[i] == 0) continue;
2684:         pblocks[nblocks++] = pblocks[i]; // nblocks always <= i
2685:         for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]);
2686:       }
2687:       PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks));
2688:     }
2689:     PetscCall(PetscFree(pblocks));
2690:   }
2691:   PetscCall(MatSetDM(*J, dm));
2692:   PetscFunctionReturn(PETSC_SUCCESS);
2693: }

2695: /*@
2696:   DMPlexGetSubdomainSection - Returns the section associated with the subdomain

2698:   Not Collective

2700:   Input Parameter:
2701: . dm - The `DMPLEX`

2703:   Output Parameter:
2704: . subsection - The subdomain section

2706:   Level: developer

2708: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection`
2709: @*/
2710: PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2711: {
2712:   DM_Plex *mesh = (DM_Plex *)dm->data;

2714:   PetscFunctionBegin;
2716:   if (!mesh->subdomainSection) {
2717:     PetscSection section;
2718:     PetscSF      sf;

2720:     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
2721:     PetscCall(DMGetLocalSection(dm, &section));
2722:     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection));
2723:     PetscCall(PetscSFDestroy(&sf));
2724:   }
2725:   *subsection = mesh->subdomainSection;
2726:   PetscFunctionReturn(PETSC_SUCCESS);
2727: }

2729: /*@
2730:   DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`)

2732:   Not Collective

2734:   Input Parameter:
2735: . dm - The `DMPLEX`

2737:   Output Parameters:
2738: + pStart - The first mesh point
2739: - pEnd   - The upper bound for mesh points

2741:   Level: beginner

2743: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`
2744: @*/
2745: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2746: {
2747:   DM_Plex *mesh = (DM_Plex *)dm->data;

2749:   PetscFunctionBegin;
2751:   if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd));
2752:   else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd));
2753:   PetscFunctionReturn(PETSC_SUCCESS);
2754: }

2756: /*@
2757:   DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`)

2759:   Not Collective

2761:   Input Parameters:
2762: + dm     - The `DMPLEX`
2763: . pStart - The first mesh point
2764: - pEnd   - The upper bound for mesh points

2766:   Level: beginner

2768: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()`
2769: @*/
2770: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2771: {
2772:   DM_Plex *mesh = (DM_Plex *)dm->data;

2774:   PetscFunctionBegin;
2776:   PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd));
2777:   PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd));
2778:   PetscCall(PetscFree(mesh->cellTypes));
2779:   PetscFunctionReturn(PETSC_SUCCESS);
2780: }

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

2785:   Not Collective

2787:   Input Parameters:
2788: + dm - The `DMPLEX`
2789: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

2791:   Output Parameter:
2792: . size - The cone size for point `p`

2794:   Level: beginner

2796: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
2797: @*/
2798: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2799: {
2800:   DM_Plex *mesh = (DM_Plex *)dm->data;

2802:   PetscFunctionBegin;
2804:   PetscAssertPointer(size, 3);
2805:   if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size));
2806:   else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size));
2807:   PetscFunctionReturn(PETSC_SUCCESS);
2808: }

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

2813:   Not Collective

2815:   Input Parameters:
2816: + dm   - The `DMPLEX`
2817: . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
2818: - size - The cone size for point `p`

2820:   Level: beginner

2822:   Note:
2823:   This should be called after `DMPlexSetChart()`.

2825: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()`
2826: @*/
2827: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2828: {
2829:   DM_Plex *mesh = (DM_Plex *)dm->data;

2831:   PetscFunctionBegin;
2833:   PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined.");
2834:   PetscCall(PetscSectionSetDof(mesh->coneSection, p, size));
2835:   PetscFunctionReturn(PETSC_SUCCESS);
2836: }

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

2841:   Not Collective

2843:   Input Parameters:
2844: + dm - The `DMPLEX`
2845: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

2847:   Output Parameter:
2848: . cone - An array of points which are on the in-edges for point `p`

2850:   Level: beginner

2852:   Fortran Notes:
2853:   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
2854:   `DMPlexRestoreCone()` is not needed/available in C.

2856: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()`
2857: @*/
2858: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2859: {
2860:   DM_Plex *mesh = (DM_Plex *)dm->data;
2861:   PetscInt off;

2863:   PetscFunctionBegin;
2865:   PetscAssertPointer(cone, 3);
2866:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
2867:   *cone = &mesh->cones[off];
2868:   PetscFunctionReturn(PETSC_SUCCESS);
2869: }

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

2874:   Not Collective

2876:   Input Parameters:
2877: + dm - The `DMPLEX`
2878: - p  - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`

2880:   Output Parameters:
2881: + pConesSection - `PetscSection` describing the layout of `pCones`
2882: - pCones        - An array of points which are on the in-edges for the point set `p`

2884:   Level: intermediate

2886: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS`
2887: @*/
2888: PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
2889: {
2890:   PetscSection cs, newcs;
2891:   PetscInt    *cones;
2892:   PetscInt    *newarr = NULL;
2893:   PetscInt     n;

2895:   PetscFunctionBegin;
2896:   PetscCall(DMPlexGetCones(dm, &cones));
2897:   PetscCall(DMPlexGetConeSection(dm, &cs));
2898:   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL));
2899:   if (pConesSection) *pConesSection = newcs;
2900:   if (pCones) {
2901:     PetscCall(PetscSectionGetStorageSize(newcs, &n));
2902:     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones));
2903:   }
2904:   PetscFunctionReturn(PETSC_SUCCESS);
2905: }

2907: /*@
2908:   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.

2910:   Not Collective

2912:   Input Parameters:
2913: + dm     - The `DMPLEX`
2914: - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`

2916:   Output Parameter:
2917: . expandedPoints - An array of vertices recursively expanded from input points

2919:   Level: advanced

2921:   Notes:
2922:   Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections.

2924:   There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate.

2926: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`,
2927:           `DMPlexGetDepth()`, `IS`
2928: @*/
2929: PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2930: {
2931:   IS      *expandedPointsAll;
2932:   PetscInt depth;

2934:   PetscFunctionBegin;
2937:   PetscAssertPointer(expandedPoints, 3);
2938:   PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2939:   *expandedPoints = expandedPointsAll[0];
2940:   PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0]));
2941:   PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL));
2942:   PetscFunctionReturn(PETSC_SUCCESS);
2943: }

2945: /*@
2946:   DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones).

2948:   Not Collective

2950:   Input Parameters:
2951: + dm     - The `DMPLEX`
2952: - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`

2954:   Output Parameters:
2955: + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
2956: . expandedPoints - (optional) An array of index sets with recursively expanded cones
2957: - sections       - (optional) An array of sections which describe mappings from points to their cone points

2959:   Level: advanced

2961:   Notes:
2962:   Like `DMPlexGetConeTuple()` but recursive.

2964:   Array `expandedPoints` has size equal to `depth`. Each `expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points.
2965:   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.

2967:   Array section has size equal to `depth`.  Each `PetscSection` `sections`[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows\:
2968:   (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d];
2969:   (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d].

2971: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
2972:           `DMPlexGetDepth()`, `PetscSection`, `IS`
2973: @*/
2974: PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2975: {
2976:   const PetscInt *arr0 = NULL, *cone = NULL;
2977:   PetscInt       *arr = NULL, *newarr = NULL;
2978:   PetscInt        d, depth_, i, n, newn, cn, co, start, end;
2979:   IS             *expandedPoints_;
2980:   PetscSection   *sections_;

2982:   PetscFunctionBegin;
2985:   if (depth) PetscAssertPointer(depth, 3);
2986:   if (expandedPoints) PetscAssertPointer(expandedPoints, 4);
2987:   if (sections) PetscAssertPointer(sections, 5);
2988:   PetscCall(ISGetLocalSize(points, &n));
2989:   PetscCall(ISGetIndices(points, &arr0));
2990:   PetscCall(DMPlexGetDepth(dm, &depth_));
2991:   PetscCall(PetscCalloc1(depth_, &expandedPoints_));
2992:   PetscCall(PetscCalloc1(depth_, &sections_));
2993:   arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */
2994:   for (d = depth_ - 1; d >= 0; d--) {
2995:     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]));
2996:     PetscCall(PetscSectionSetChart(sections_[d], 0, n));
2997:     for (i = 0; i < n; i++) {
2998:       PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end));
2999:       if (arr[i] >= start && arr[i] < end) {
3000:         PetscCall(DMPlexGetConeSize(dm, arr[i], &cn));
3001:         PetscCall(PetscSectionSetDof(sections_[d], i, cn));
3002:       } else {
3003:         PetscCall(PetscSectionSetDof(sections_[d], i, 1));
3004:       }
3005:     }
3006:     PetscCall(PetscSectionSetUp(sections_[d]));
3007:     PetscCall(PetscSectionGetStorageSize(sections_[d], &newn));
3008:     PetscCall(PetscMalloc1(newn, &newarr));
3009:     for (i = 0; i < n; i++) {
3010:       PetscCall(PetscSectionGetDof(sections_[d], i, &cn));
3011:       PetscCall(PetscSectionGetOffset(sections_[d], i, &co));
3012:       if (cn > 1) {
3013:         PetscCall(DMPlexGetCone(dm, arr[i], &cone));
3014:         PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt)));
3015:       } else {
3016:         newarr[co] = arr[i];
3017:       }
3018:     }
3019:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]));
3020:     arr = newarr;
3021:     n   = newn;
3022:   }
3023:   PetscCall(ISRestoreIndices(points, &arr0));
3024:   *depth = depth_;
3025:   if (expandedPoints) *expandedPoints = expandedPoints_;
3026:   else {
3027:     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d]));
3028:     PetscCall(PetscFree(expandedPoints_));
3029:   }
3030:   if (sections) *sections = sections_;
3031:   else {
3032:     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&sections_[d]));
3033:     PetscCall(PetscFree(sections_));
3034:   }
3035:   PetscFunctionReturn(PETSC_SUCCESS);
3036: }

3038: /*@
3039:   DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()`

3041:   Not Collective

3043:   Input Parameters:
3044: + dm     - The `DMPLEX`
3045: - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()`

3047:   Output Parameters:
3048: + depth          - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()`
3049: . expandedPoints - (optional) An array of recursively expanded cones
3050: - sections       - (optional) An array of sections which describe mappings from points to their cone points

3052:   Level: advanced

3054:   Note:
3055:   See `DMPlexGetConeRecursive()`

3057: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`,
3058:           `DMPlexGetDepth()`, `IS`, `PetscSection`
3059: @*/
3060: PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
3061: {
3062:   PetscInt d, depth_;

3064:   PetscFunctionBegin;
3065:   PetscCall(DMPlexGetDepth(dm, &depth_));
3066:   PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
3067:   if (depth) *depth = 0;
3068:   if (expandedPoints) {
3069:     for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d])));
3070:     PetscCall(PetscFree(*expandedPoints));
3071:   }
3072:   if (sections) {
3073:     for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d])));
3074:     PetscCall(PetscFree(*sections));
3075:   }
3076:   PetscFunctionReturn(PETSC_SUCCESS);
3077: }

3079: /*@
3080:   DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point

3082:   Not Collective

3084:   Input Parameters:
3085: + dm   - The `DMPLEX`
3086: . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3087: - cone - An array of points which are on the in-edges for point `p`

3089:   Level: beginner

3091:   Note:
3092:   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.

3094: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()`
3095: @*/
3096: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
3097: {
3098:   DM_Plex *mesh = (DM_Plex *)dm->data;
3099:   PetscInt dof, off, c;

3101:   PetscFunctionBegin;
3103:   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3104:   if (dof) PetscAssertPointer(cone, 3);
3105:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3106:   if (PetscDefined(USE_DEBUG)) {
3107:     PetscInt pStart, pEnd;
3108:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3109:     PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3110:     for (c = 0; c < dof; ++c) {
3111:       PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd);
3112:       mesh->cones[off + c] = cone[c];
3113:     }
3114:   } else {
3115:     for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c];
3116:   }
3117:   PetscFunctionReturn(PETSC_SUCCESS);
3118: }

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

3123:   Not Collective

3125:   Input Parameters:
3126: + dm - The `DMPLEX`
3127: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

3129:   Output Parameter:
3130: . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an
3131:                     integer giving the prescription for cone traversal.

3133:   Level: beginner

3135:   Note:
3136:   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3137:   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3138:   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3139:   with the identity.

3141:   Fortran Notes:
3142:   You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array.
3143:   `DMPlexRestoreConeOrientation()` is not needed/available in C.

3145: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()`
3146: @*/
3147: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
3148: {
3149:   DM_Plex *mesh = (DM_Plex *)dm->data;
3150:   PetscInt off;

3152:   PetscFunctionBegin;
3154:   if (PetscDefined(USE_DEBUG)) {
3155:     PetscInt dof;
3156:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3157:     if (dof) PetscAssertPointer(coneOrientation, 3);
3158:   }
3159:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));

3161:   *coneOrientation = &mesh->coneOrientations[off];
3162:   PetscFunctionReturn(PETSC_SUCCESS);
3163: }

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

3168:   Not Collective

3170:   Input Parameters:
3171: + dm              - The `DMPLEX`
3172: . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
3173: - coneOrientation - An array of orientations

3175:   Level: beginner

3177:   Notes:
3178:   This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`.

3180:   The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`.

3182: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3183: @*/
3184: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3185: {
3186:   DM_Plex *mesh = (DM_Plex *)dm->data;
3187:   PetscInt pStart, pEnd;
3188:   PetscInt dof, off, c;

3190:   PetscFunctionBegin;
3192:   PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3193:   if (dof) PetscAssertPointer(coneOrientation, 3);
3194:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3195:   if (PetscDefined(USE_DEBUG)) {
3196:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3197:     PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3198:     for (c = 0; c < dof; ++c) {
3199:       PetscInt cdof, o = coneOrientation[c];

3201:       PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof));
3202:       PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof);
3203:       mesh->coneOrientations[off + c] = o;
3204:     }
3205:   } else {
3206:     for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c];
3207:   }
3208:   PetscFunctionReturn(PETSC_SUCCESS);
3209: }

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

3214:   Not Collective

3216:   Input Parameters:
3217: + dm        - The `DMPLEX`
3218: . p         - The point, which must lie in the chart set with `DMPlexSetChart()`
3219: . conePos   - The local index in the cone where the point should be put
3220: - conePoint - The mesh point to insert

3222:   Level: beginner

3224: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3225: @*/
3226: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3227: {
3228:   DM_Plex *mesh = (DM_Plex *)dm->data;
3229:   PetscInt pStart, pEnd;
3230:   PetscInt dof, off;

3232:   PetscFunctionBegin;
3234:   if (PetscDefined(USE_DEBUG)) {
3235:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3236:     PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3237:     PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd);
3238:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3239:     PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof);
3240:   }
3241:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3242:   mesh->cones[off + conePos] = conePoint;
3243:   PetscFunctionReturn(PETSC_SUCCESS);
3244: }

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

3249:   Not Collective

3251:   Input Parameters:
3252: + dm              - The `DMPLEX`
3253: . p               - The point, which must lie in the chart set with `DMPlexSetChart()`
3254: . conePos         - The local index in the cone where the point should be put
3255: - coneOrientation - The point orientation to insert

3257:   Level: beginner

3259:   Note:
3260:   The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`.

3262: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3263: @*/
3264: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3265: {
3266:   DM_Plex *mesh = (DM_Plex *)dm->data;
3267:   PetscInt pStart, pEnd;
3268:   PetscInt dof, off;

3270:   PetscFunctionBegin;
3272:   if (PetscDefined(USE_DEBUG)) {
3273:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
3274:     PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3275:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3276:     PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof);
3277:   }
3278:   PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3279:   mesh->coneOrientations[off + conePos] = coneOrientation;
3280:   PetscFunctionReturn(PETSC_SUCCESS);
3281: }

3283: /*@C
3284:   DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG

3286:   Not collective

3288:   Input Parameters:
3289: + dm - The DMPlex
3290: - p  - The point, which must lie in the chart set with DMPlexSetChart()

3292:   Output Parameters:
3293: + cone - An array of points which are on the in-edges for point `p`
3294: - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
3295:         integer giving the prescription for cone traversal.

3297:   Level: beginner

3299:   Notes:
3300:   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3301:   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3302:   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3303:   with the identity.

3305:   Fortran Notes:
3306:   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
3307:   `DMPlexRestoreCone()` is not needed/available in C.

3309: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3310: @*/
3311: PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3312: {
3313:   DM_Plex *mesh = (DM_Plex *)dm->data;

3315:   PetscFunctionBegin;
3317:   if (mesh->tr) {
3318:     PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt));
3319:   } else {
3320:     PetscInt off;
3321:     if (PetscDefined(USE_DEBUG)) {
3322:       PetscInt dof;
3323:       PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
3324:       if (dof) {
3325:         if (cone) PetscAssertPointer(cone, 3);
3326:         if (ornt) PetscAssertPointer(ornt, 4);
3327:       }
3328:     }
3329:     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
3330:     if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB
3331:     if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL;
3332:   }
3333:   PetscFunctionReturn(PETSC_SUCCESS);
3334: }

3336: /*@C
3337:   DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG

3339:   Not Collective

3341:   Input Parameters:
3342: + dm   - The DMPlex
3343: . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3344: . cone - An array of points which are on the in-edges for point p
3345: - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an
3346:         integer giving the prescription for cone traversal.

3348:   Level: beginner

3350:   Notes:
3351:   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
3352:   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
3353:   of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()`
3354:   with the identity.

3356:   Fortran Notes:
3357:   You must also call `DMPlexRestoreCone()` after you finish using the returned array.
3358:   `DMPlexRestoreCone()` is not needed/available in C.

3360: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()`
3361: @*/
3362: PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[])
3363: {
3364:   DM_Plex *mesh = (DM_Plex *)dm->data;

3366:   PetscFunctionBegin;
3368:   if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt));
3369:   PetscFunctionReturn(PETSC_SUCCESS);
3370: }

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

3375:   Not Collective

3377:   Input Parameters:
3378: + dm - The `DMPLEX`
3379: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

3381:   Output Parameter:
3382: . size - The support size for point `p`

3384:   Level: beginner

3386: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()`
3387: @*/
3388: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3389: {
3390:   DM_Plex *mesh = (DM_Plex *)dm->data;

3392:   PetscFunctionBegin;
3394:   PetscAssertPointer(size, 3);
3395:   PetscCall(PetscSectionGetDof(mesh->supportSection, p, size));
3396:   PetscFunctionReturn(PETSC_SUCCESS);
3397: }

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

3402:   Not Collective

3404:   Input Parameters:
3405: + dm   - The `DMPLEX`
3406: . p    - The point, which must lie in the chart set with `DMPlexSetChart()`
3407: - size - The support size for point `p`

3409:   Level: beginner

3411:   Note:
3412:   This should be called after `DMPlexSetChart()`.

3414: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()`
3415: @*/
3416: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3417: {
3418:   DM_Plex *mesh = (DM_Plex *)dm->data;

3420:   PetscFunctionBegin;
3422:   PetscCall(PetscSectionSetDof(mesh->supportSection, p, size));
3423:   PetscFunctionReturn(PETSC_SUCCESS);
3424: }

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

3429:   Not Collective

3431:   Input Parameters:
3432: + dm - The `DMPLEX`
3433: - p  - The point, which must lie in the chart set with `DMPlexSetChart()`

3435:   Output Parameter:
3436: . support - An array of points which are on the out-edges for point `p`

3438:   Level: beginner

3440:   Fortran Notes:
3441:   You must also call `DMPlexRestoreSupport()` after you finish using the returned array.
3442:   `DMPlexRestoreSupport()` is not needed/available in C.

3444: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()`
3445: @*/
3446: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3447: {
3448:   DM_Plex *mesh = (DM_Plex *)dm->data;
3449:   PetscInt off;

3451:   PetscFunctionBegin;
3453:   PetscAssertPointer(support, 3);
3454:   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3455:   *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB
3456:   PetscFunctionReturn(PETSC_SUCCESS);
3457: }

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

3462:   Not Collective

3464:   Input Parameters:
3465: + dm      - The `DMPLEX`
3466: . p       - The point, which must lie in the chart set with `DMPlexSetChart()`
3467: - support - An array of points which are on the out-edges for point `p`

3469:   Level: beginner

3471:   Note:
3472:   This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`.

3474: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()`
3475: @*/
3476: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3477: {
3478:   DM_Plex *mesh = (DM_Plex *)dm->data;
3479:   PetscInt pStart, pEnd;
3480:   PetscInt dof, off, c;

3482:   PetscFunctionBegin;
3484:   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3485:   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3486:   if (dof) PetscAssertPointer(support, 3);
3487:   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3488:   PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3489:   for (c = 0; c < dof; ++c) {
3490:     PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd);
3491:     mesh->supports[off + c] = support[c];
3492:   }
3493:   PetscFunctionReturn(PETSC_SUCCESS);
3494: }

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

3499:   Not Collective

3501:   Input Parameters:
3502: + dm           - The `DMPLEX`
3503: . p            - The point, which must lie in the chart set with `DMPlexSetChart()`
3504: . supportPos   - The local index in the cone where the point should be put
3505: - supportPoint - The mesh point to insert

3507:   Level: beginner

3509: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`
3510: @*/
3511: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3512: {
3513:   DM_Plex *mesh = (DM_Plex *)dm->data;
3514:   PetscInt pStart, pEnd;
3515:   PetscInt dof, off;

3517:   PetscFunctionBegin;
3519:   PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd));
3520:   PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof));
3521:   PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off));
3522:   PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd);
3523:   PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd);
3524:   PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof);
3525:   mesh->supports[off + supportPos] = supportPoint;
3526:   PetscFunctionReturn(PETSC_SUCCESS);
3527: }

3529: /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3530: PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3531: {
3532:   switch (ct) {
3533:   case DM_POLYTOPE_SEGMENT:
3534:     if (o == -1) return -2;
3535:     break;
3536:   case DM_POLYTOPE_TRIANGLE:
3537:     if (o == -3) return -1;
3538:     if (o == -2) return -3;
3539:     if (o == -1) return -2;
3540:     break;
3541:   case DM_POLYTOPE_QUADRILATERAL:
3542:     if (o == -4) return -2;
3543:     if (o == -3) return -1;
3544:     if (o == -2) return -4;
3545:     if (o == -1) return -3;
3546:     break;
3547:   default:
3548:     return o;
3549:   }
3550:   return o;
3551: }

3553: /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3554: PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3555: {
3556:   switch (ct) {
3557:   case DM_POLYTOPE_SEGMENT:
3558:     if ((o == -2) || (o == 1)) return -1;
3559:     if (o == -1) return 0;
3560:     break;
3561:   case DM_POLYTOPE_TRIANGLE:
3562:     if (o == -3) return -2;
3563:     if (o == -2) return -1;
3564:     if (o == -1) return -3;
3565:     break;
3566:   case DM_POLYTOPE_QUADRILATERAL:
3567:     if (o == -4) return -2;
3568:     if (o == -3) return -1;
3569:     if (o == -2) return -4;
3570:     if (o == -1) return -3;
3571:     break;
3572:   default:
3573:     return o;
3574:   }
3575:   return o;
3576: }

3578: /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3579: PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3580: {
3581:   PetscInt pStart, pEnd, p;

3583:   PetscFunctionBegin;
3584:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3585:   for (p = pStart; p < pEnd; ++p) {
3586:     const PetscInt *cone, *ornt;
3587:     PetscInt        coneSize, c;

3589:     PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
3590:     PetscCall(DMPlexGetCone(dm, p, &cone));
3591:     PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
3592:     for (c = 0; c < coneSize; ++c) {
3593:       DMPolytopeType ct;
3594:       const PetscInt o = ornt[c];

3596:       PetscCall(DMPlexGetCellType(dm, cone[c], &ct));
3597:       switch (ct) {
3598:       case DM_POLYTOPE_SEGMENT:
3599:         if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3600:         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0));
3601:         break;
3602:       case DM_POLYTOPE_TRIANGLE:
3603:         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
3604:         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3605:         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3606:         break;
3607:       case DM_POLYTOPE_QUADRILATERAL:
3608:         if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2));
3609:         if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1));
3610:         if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4));
3611:         if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3));
3612:         break;
3613:       default:
3614:         break;
3615:       }
3616:     }
3617:   }
3618:   PetscFunctionReturn(PETSC_SUCCESS);
3619: }

3621: static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
3622: {
3623:   DM_Plex *mesh = (DM_Plex *)dm->data;

3625:   PetscFunctionBeginHot;
3626:   if (PetscDefined(USE_DEBUG) || mesh->tr) {
3627:     if (useCone) {
3628:       PetscCall(DMPlexGetConeSize(dm, p, size));
3629:       PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt));
3630:     } else {
3631:       PetscCall(DMPlexGetSupportSize(dm, p, size));
3632:       PetscCall(DMPlexGetSupport(dm, p, arr));
3633:     }
3634:   } else {
3635:     if (useCone) {
3636:       const PetscSection s   = mesh->coneSection;
3637:       const PetscInt     ps  = p - s->pStart;
3638:       const PetscInt     off = s->atlasOff[ps];

3640:       *size = s->atlasDof[ps];
3641:       *arr  = mesh->cones + off;
3642:       *ornt = mesh->coneOrientations + off;
3643:     } else {
3644:       const PetscSection s   = mesh->supportSection;
3645:       const PetscInt     ps  = p - s->pStart;
3646:       const PetscInt     off = s->atlasOff[ps];

3648:       *size = s->atlasDof[ps];
3649:       *arr  = mesh->supports + off;
3650:     }
3651:   }
3652:   PetscFunctionReturn(PETSC_SUCCESS);
3653: }

3655: static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[])
3656: {
3657:   DM_Plex *mesh = (DM_Plex *)dm->data;

3659:   PetscFunctionBeginHot;
3660:   if (PetscDefined(USE_DEBUG) || mesh->tr) {
3661:     if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt));
3662:   }
3663:   PetscFunctionReturn(PETSC_SUCCESS);
3664: }

3666: static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3667: {
3668:   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3669:   PetscInt       *closure;
3670:   const PetscInt *tmp = NULL, *tmpO = NULL;
3671:   PetscInt        off = 0, tmpSize, t;

3673:   PetscFunctionBeginHot;
3674:   if (ornt) {
3675:     PetscCall(DMPlexGetCellType(dm, p, &ct));
3676:     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3677:   }
3678:   if (*points) {
3679:     closure = *points;
3680:   } else {
3681:     PetscInt maxConeSize, maxSupportSize;
3682:     PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3683:     PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure));
3684:   }
3685:   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3686:   if (ct == DM_POLYTOPE_UNKNOWN) {
3687:     closure[off++] = p;
3688:     closure[off++] = 0;
3689:     for (t = 0; t < tmpSize; ++t) {
3690:       closure[off++] = tmp[t];
3691:       closure[off++] = tmpO ? tmpO[t] : 0;
3692:     }
3693:   } else {
3694:     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);

3696:     /* We assume that cells with a valid type have faces with a valid type */
3697:     closure[off++] = p;
3698:     closure[off++] = ornt;
3699:     for (t = 0; t < tmpSize; ++t) {
3700:       DMPolytopeType ft;

3702:       PetscCall(DMPlexGetCellType(dm, tmp[t], &ft));
3703:       closure[off++] = tmp[arr[t]];
3704:       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3705:     }
3706:   }
3707:   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO));
3708:   if (numPoints) *numPoints = tmpSize + 1;
3709:   if (points) *points = closure;
3710:   PetscFunctionReturn(PETSC_SUCCESS);
3711: }

3713: /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */
3714: static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3715: {
3716:   const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3717:   const PetscInt *cone, *ornt;
3718:   PetscInt       *pts, *closure = NULL;
3719:   DMPolytopeType  ft;
3720:   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3721:   PetscInt        dim, coneSize, c, d, clSize, cl;

3723:   PetscFunctionBeginHot;
3724:   PetscCall(DMGetDimension(dm, &dim));
3725:   PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3726:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3727:   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1;
3728:   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1;
3729:   maxSize       = PetscMax(coneSeries, supportSeries);
3730:   if (*points) {
3731:     pts = *points;
3732:   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts));
3733:   c        = 0;
3734:   pts[c++] = point;
3735:   pts[c++] = o;
3736:   PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft));
3737:   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure));
3738:   for (cl = 0; cl < clSize * 2; cl += 2) {
3739:     pts[c++] = closure[cl];
3740:     pts[c++] = closure[cl + 1];
3741:   }
3742:   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure));
3743:   for (cl = 0; cl < clSize * 2; cl += 2) {
3744:     pts[c++] = closure[cl];
3745:     pts[c++] = closure[cl + 1];
3746:   }
3747:   PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure));
3748:   for (d = 2; d < coneSize; ++d) {
3749:     PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft));
3750:     pts[c++] = cone[arr[d * 2 + 0]];
3751:     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]);
3752:   }
3753:   PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt));
3754:   if (dim >= 3) {
3755:     for (d = 2; d < coneSize; ++d) {
3756:       const PetscInt  fpoint = cone[arr[d * 2 + 0]];
3757:       const PetscInt *fcone, *fornt;
3758:       PetscInt        fconeSize, fc, i;

3760:       PetscCall(DMPlexGetCellType(dm, fpoint, &ft));
3761:       const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]));
3762:       PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3763:       for (fc = 0; fc < fconeSize; ++fc) {
3764:         const PetscInt cp = fcone[farr[fc * 2 + 0]];
3765:         const PetscInt co = farr[fc * 2 + 1];

3767:         for (i = 0; i < c; i += 2)
3768:           if (pts[i] == cp) break;
3769:         if (i == c) {
3770:           PetscCall(DMPlexGetCellType(dm, cp, &ft));
3771:           pts[c++] = cp;
3772:           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]);
3773:         }
3774:       }
3775:       PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt));
3776:     }
3777:   }
3778:   *numPoints = c / 2;
3779:   *points    = pts;
3780:   PetscFunctionReturn(PETSC_SUCCESS);
3781: }

3783: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3784: {
3785:   DMPolytopeType ct;
3786:   PetscInt      *closure, *fifo;
3787:   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3788:   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3789:   PetscInt       depth, maxSize;

3791:   PetscFunctionBeginHot;
3792:   PetscCall(DMPlexGetDepth(dm, &depth));
3793:   if (depth == 1) {
3794:     PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points));
3795:     PetscFunctionReturn(PETSC_SUCCESS);
3796:   }
3797:   PetscCall(DMPlexGetCellType(dm, p, &ct));
3798:   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3799:   if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
3800:     PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points));
3801:     PetscFunctionReturn(PETSC_SUCCESS);
3802:   }
3803:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
3804:   coneSeries    = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1;
3805:   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1;
3806:   maxSize       = PetscMax(coneSeries, supportSeries);
3807:   PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
3808:   if (*points) {
3809:     closure = *points;
3810:   } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure));
3811:   closure[closureSize++] = p;
3812:   closure[closureSize++] = ornt;
3813:   fifo[fifoSize++]       = p;
3814:   fifo[fifoSize++]       = ornt;
3815:   fifo[fifoSize++]       = ct;
3816:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3817:   while (fifoSize - fifoStart) {
3818:     const PetscInt       q    = fifo[fifoStart++];
3819:     const PetscInt       o    = fifo[fifoStart++];
3820:     const DMPolytopeType qt   = (DMPolytopeType)fifo[fifoStart++];
3821:     const PetscInt      *qarr = DMPolytopeTypeGetArrangment(qt, o);
3822:     const PetscInt      *tmp, *tmpO = NULL;
3823:     PetscInt             tmpSize, t;

3825:     if (PetscDefined(USE_DEBUG)) {
3826:       PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2;
3827:       PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q);
3828:     }
3829:     PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
3830:     for (t = 0; t < tmpSize; ++t) {
3831:       const PetscInt ip = useCone && qarr ? qarr[t * 2] : t;
3832:       const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0;
3833:       const PetscInt cp = tmp[ip];
3834:       PetscCall(DMPlexGetCellType(dm, cp, &ct));
3835:       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3836:       PetscInt       c;

3838:       /* Check for duplicate */
3839:       for (c = 0; c < closureSize; c += 2) {
3840:         if (closure[c] == cp) break;
3841:       }
3842:       if (c == closureSize) {
3843:         closure[closureSize++] = cp;
3844:         closure[closureSize++] = co;
3845:         fifo[fifoSize++]       = cp;
3846:         fifo[fifoSize++]       = co;
3847:         fifo[fifoSize++]       = ct;
3848:       }
3849:     }
3850:     PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO));
3851:   }
3852:   PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo));
3853:   if (numPoints) *numPoints = closureSize / 2;
3854:   if (points) *points = closure;
3855:   PetscFunctionReturn(PETSC_SUCCESS);
3856: }

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

3861:   Not Collective

3863:   Input Parameters:
3864: + dm      - The `DMPLEX`
3865: . p       - The mesh point
3866: - useCone - `PETSC_TRUE` for the closure, otherwise return the star

3868:   Input/Output Parameter:
3869: . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
3870:            if `NULL` on input, internal storage will be returned, otherwise the provided array is used

3872:   Output Parameter:
3873: . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`

3875:   Level: beginner

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

3880:   Fortran Notes:
3881:   The `numPoints` argument is not present in the Fortran binding since it is internal to the array.

3883: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3884: @*/
3885: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3886: {
3887:   PetscFunctionBeginHot;
3889:   if (numPoints) PetscAssertPointer(numPoints, 4);
3890:   if (points) PetscAssertPointer(points, 5);
3891:   PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points));
3892:   PetscFunctionReturn(PETSC_SUCCESS);
3893: }

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

3898:   Not Collective

3900:   Input Parameters:
3901: + dm        - The `DMPLEX`
3902: . p         - The mesh point
3903: . useCone   - `PETSC_TRUE` for the closure, otherwise return the star
3904: . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints`
3905: - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]

3907:   Level: beginner

3909:   Note:
3910:   If not using internal storage (points is not `NULL` on input), this call is unnecessary

3912: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()`
3913: @*/
3914: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3915: {
3916:   PetscFunctionBeginHot;
3918:   if (numPoints) *numPoints = 0;
3919:   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points));
3920:   PetscFunctionReturn(PETSC_SUCCESS);
3921: }

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

3926:   Not Collective

3928:   Input Parameter:
3929: . dm - The `DMPLEX`

3931:   Output Parameters:
3932: + maxConeSize    - The maximum number of in-edges
3933: - maxSupportSize - The maximum number of out-edges

3935:   Level: beginner

3937: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`
3938: @*/
3939: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3940: {
3941:   DM_Plex *mesh = (DM_Plex *)dm->data;

3943:   PetscFunctionBegin;
3945:   if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize));
3946:   if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize));
3947:   PetscFunctionReturn(PETSC_SUCCESS);
3948: }

3950: PetscErrorCode DMSetUp_Plex(DM dm)
3951: {
3952:   DM_Plex *mesh = (DM_Plex *)dm->data;
3953:   PetscInt size, maxSupportSize;

3955:   PetscFunctionBegin;
3957:   PetscCall(PetscSectionSetUp(mesh->coneSection));
3958:   PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size));
3959:   PetscCall(PetscMalloc1(size, &mesh->cones));
3960:   PetscCall(PetscCalloc1(size, &mesh->coneOrientations));
3961:   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
3962:   if (maxSupportSize) {
3963:     PetscCall(PetscSectionSetUp(mesh->supportSection));
3964:     PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size));
3965:     PetscCall(PetscMalloc1(size, &mesh->supports));
3966:   }
3967:   PetscFunctionReturn(PETSC_SUCCESS);
3968: }

3970: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3971: {
3972:   PetscFunctionBegin;
3973:   if (subdm) PetscCall(DMClone(dm, subdm));
3974:   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
3975:   if (subdm) (*subdm)->useNatural = dm->useNatural;
3976:   if (dm->useNatural && dm->sfMigration) {
3977:     PetscSF sfNatural;

3979:     (*subdm)->sfMigration = dm->sfMigration;
3980:     PetscCall(PetscObjectReference((PetscObject)dm->sfMigration));
3981:     PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural));
3982:     (*subdm)->sfNatural = sfNatural;
3983:   }
3984:   PetscFunctionReturn(PETSC_SUCCESS);
3985: }

3987: PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
3988: {
3989:   PetscInt i = 0;

3991:   PetscFunctionBegin;
3992:   PetscCall(DMClone(dms[0], superdm));
3993:   PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm));
3994:   (*superdm)->useNatural = PETSC_FALSE;
3995:   for (i = 0; i < len; i++) {
3996:     if (dms[i]->useNatural && dms[i]->sfMigration) {
3997:       PetscSF sfNatural;

3999:       (*superdm)->sfMigration = dms[i]->sfMigration;
4000:       PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration));
4001:       (*superdm)->useNatural = PETSC_TRUE;
4002:       PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural));
4003:       (*superdm)->sfNatural = sfNatural;
4004:       break;
4005:     }
4006:   }
4007:   PetscFunctionReturn(PETSC_SUCCESS);
4008: }

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

4013:   Not Collective

4015:   Input Parameter:
4016: . dm - The `DMPLEX`

4018:   Level: beginner

4020:   Note:
4021:   This should be called after all calls to `DMPlexSetCone()`

4023: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()`
4024: @*/
4025: PetscErrorCode DMPlexSymmetrize(DM dm)
4026: {
4027:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4028:   PetscInt *offsets;
4029:   PetscInt  supportSize;
4030:   PetscInt  pStart, pEnd, p;

4032:   PetscFunctionBegin;
4034:   PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
4035:   PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0));
4036:   /* Calculate support sizes */
4037:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4038:   for (p = pStart; p < pEnd; ++p) {
4039:     PetscInt dof, off, c;

4041:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
4042:     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4043:     for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1));
4044:   }
4045:   PetscCall(PetscSectionSetUp(mesh->supportSection));
4046:   /* Calculate supports */
4047:   PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize));
4048:   PetscCall(PetscMalloc1(supportSize, &mesh->supports));
4049:   PetscCall(PetscCalloc1(pEnd - pStart, &offsets));
4050:   for (p = pStart; p < pEnd; ++p) {
4051:     PetscInt dof, off, c;

4053:     PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof));
4054:     PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off));
4055:     for (c = off; c < off + dof; ++c) {
4056:       const PetscInt q = mesh->cones[c];
4057:       PetscInt       offS;

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

4061:       mesh->supports[offS + offsets[q]] = p;
4062:       ++offsets[q];
4063:     }
4064:   }
4065:   PetscCall(PetscFree(offsets));
4066:   PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0));
4067:   PetscFunctionReturn(PETSC_SUCCESS);
4068: }

4070: static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
4071: {
4072:   IS stratumIS;

4074:   PetscFunctionBegin;
4075:   if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS);
4076:   if (PetscDefined(USE_DEBUG)) {
4077:     PetscInt  qStart, qEnd, numLevels, level;
4078:     PetscBool overlap = PETSC_FALSE;
4079:     PetscCall(DMLabelGetNumValues(label, &numLevels));
4080:     for (level = 0; level < numLevels; level++) {
4081:       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4082:       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {
4083:         overlap = PETSC_TRUE;
4084:         break;
4085:       }
4086:     }
4087:     PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd);
4088:   }
4089:   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS));
4090:   PetscCall(DMLabelSetStratumIS(label, depth, stratumIS));
4091:   PetscCall(ISDestroy(&stratumIS));
4092:   PetscFunctionReturn(PETSC_SUCCESS);
4093: }

4095: /*@
4096:   DMPlexStratify - Computes the strata for all points in the `DMPLEX`

4098:   Collective

4100:   Input Parameter:
4101: . dm - The `DMPLEX`

4103:   Level: beginner

4105:   Notes:
4106:   The strata group all points of the same grade, and this function calculates the strata. This
4107:   grade can be seen as the height (or depth) of the point in the DAG.

4109:   The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
4110:   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram).
4111:   Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
4112:   meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
4113:   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or
4114:   manually via `DMGetLabel()`.  The height is defined implicitly by height = maxDimension - depth, and can be accessed
4115:   via `DMPlexGetHeightStratum()`.  For example, cells have height 0 and faces have height 1.

4117:   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
4118:   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
4119:   we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose
4120:   to interpolate only that one (e0), so that
4121: .vb
4122:   cone(c0) = {e0, v2}
4123:   cone(e0) = {v0, v1}
4124: .ve
4125:   If `DMPlexStratify()` is run on this mesh, it will give depths
4126: .vb
4127:    depth 0 = {v0, v1, v2}
4128:    depth 1 = {e0, c0}
4129: .ve
4130:   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.

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

4134: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()`
4135: @*/
4136: PetscErrorCode DMPlexStratify(DM dm)
4137: {
4138:   DM_Plex *mesh = (DM_Plex *)dm->data;
4139:   DMLabel  label;
4140:   PetscInt pStart, pEnd, p;
4141:   PetscInt numRoots = 0, numLeaves = 0;

4143:   PetscFunctionBegin;
4145:   PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0));

4147:   /* Create depth label */
4148:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4149:   PetscCall(DMCreateLabel(dm, "depth"));
4150:   PetscCall(DMPlexGetDepthLabel(dm, &label));

4152:   {
4153:     /* Initialize roots and count leaves */
4154:     PetscInt sMin = PETSC_MAX_INT;
4155:     PetscInt sMax = PETSC_MIN_INT;
4156:     PetscInt coneSize, supportSize;

4158:     for (p = pStart; p < pEnd; ++p) {
4159:       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4160:       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4161:       if (!coneSize && supportSize) {
4162:         sMin = PetscMin(p, sMin);
4163:         sMax = PetscMax(p, sMax);
4164:         ++numRoots;
4165:       } else if (!supportSize && coneSize) {
4166:         ++numLeaves;
4167:       } else if (!supportSize && !coneSize) {
4168:         /* Isolated points */
4169:         sMin = PetscMin(p, sMin);
4170:         sMax = PetscMax(p, sMax);
4171:       }
4172:     }
4173:     PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1));
4174:   }

4176:   if (numRoots + numLeaves == (pEnd - pStart)) {
4177:     PetscInt sMin = PETSC_MAX_INT;
4178:     PetscInt sMax = PETSC_MIN_INT;
4179:     PetscInt coneSize, supportSize;

4181:     for (p = pStart; p < pEnd; ++p) {
4182:       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4183:       PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
4184:       if (!supportSize && coneSize) {
4185:         sMin = PetscMin(p, sMin);
4186:         sMax = PetscMax(p, sMax);
4187:       }
4188:     }
4189:     PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1));
4190:   } else {
4191:     PetscInt level = 0;
4192:     PetscInt qStart, qEnd, q;

4194:     PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4195:     while (qEnd > qStart) {
4196:       PetscInt sMin = PETSC_MAX_INT;
4197:       PetscInt sMax = PETSC_MIN_INT;

4199:       for (q = qStart; q < qEnd; ++q) {
4200:         const PetscInt *support;
4201:         PetscInt        supportSize, s;

4203:         PetscCall(DMPlexGetSupportSize(dm, q, &supportSize));
4204:         PetscCall(DMPlexGetSupport(dm, q, &support));
4205:         for (s = 0; s < supportSize; ++s) {
4206:           sMin = PetscMin(support[s], sMin);
4207:           sMax = PetscMax(support[s], sMax);
4208:         }
4209:       }
4210:       PetscCall(DMLabelGetNumValues(label, &level));
4211:       PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1));
4212:       PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd));
4213:     }
4214:   }
4215:   { /* just in case there is an empty process */
4216:     PetscInt numValues, maxValues = 0, v;

4218:     PetscCall(DMLabelGetNumValues(label, &numValues));
4219:     PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
4220:     for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v));
4221:   }
4222:   PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState));
4223:   PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0));
4224:   PetscFunctionReturn(PETSC_SUCCESS);
4225: }

4227: PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
4228: {
4229:   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4230:   PetscInt       dim, depth, pheight, coneSize;

4232:   PetscFunctionBeginHot;
4233:   PetscCall(DMGetDimension(dm, &dim));
4234:   PetscCall(DMPlexGetDepth(dm, &depth));
4235:   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
4236:   pheight = depth - pdepth;
4237:   if (depth <= 1) {
4238:     switch (pdepth) {
4239:     case 0:
4240:       ct = DM_POLYTOPE_POINT;
4241:       break;
4242:     case 1:
4243:       switch (coneSize) {
4244:       case 2:
4245:         ct = DM_POLYTOPE_SEGMENT;
4246:         break;
4247:       case 3:
4248:         ct = DM_POLYTOPE_TRIANGLE;
4249:         break;
4250:       case 4:
4251:         switch (dim) {
4252:         case 2:
4253:           ct = DM_POLYTOPE_QUADRILATERAL;
4254:           break;
4255:         case 3:
4256:           ct = DM_POLYTOPE_TETRAHEDRON;
4257:           break;
4258:         default:
4259:           break;
4260:         }
4261:         break;
4262:       case 5:
4263:         ct = DM_POLYTOPE_PYRAMID;
4264:         break;
4265:       case 6:
4266:         ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4267:         break;
4268:       case 8:
4269:         ct = DM_POLYTOPE_HEXAHEDRON;
4270:         break;
4271:       default:
4272:         break;
4273:       }
4274:     }
4275:   } else {
4276:     if (pdepth == 0) {
4277:       ct = DM_POLYTOPE_POINT;
4278:     } else if (pheight == 0) {
4279:       switch (dim) {
4280:       case 1:
4281:         switch (coneSize) {
4282:         case 2:
4283:           ct = DM_POLYTOPE_SEGMENT;
4284:           break;
4285:         default:
4286:           break;
4287:         }
4288:         break;
4289:       case 2:
4290:         switch (coneSize) {
4291:         case 3:
4292:           ct = DM_POLYTOPE_TRIANGLE;
4293:           break;
4294:         case 4:
4295:           ct = DM_POLYTOPE_QUADRILATERAL;
4296:           break;
4297:         default:
4298:           break;
4299:         }
4300:         break;
4301:       case 3:
4302:         switch (coneSize) {
4303:         case 4:
4304:           ct = DM_POLYTOPE_TETRAHEDRON;
4305:           break;
4306:         case 5: {
4307:           const PetscInt *cone;
4308:           PetscInt        faceConeSize;

4310:           PetscCall(DMPlexGetCone(dm, p, &cone));
4311:           PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize));
4312:           switch (faceConeSize) {
4313:           case 3:
4314:             ct = DM_POLYTOPE_TRI_PRISM_TENSOR;
4315:             break;
4316:           case 4:
4317:             ct = DM_POLYTOPE_PYRAMID;
4318:             break;
4319:           }
4320:         } break;
4321:         case 6:
4322:           ct = DM_POLYTOPE_HEXAHEDRON;
4323:           break;
4324:         default:
4325:           break;
4326:         }
4327:         break;
4328:       default:
4329:         break;
4330:       }
4331:     } else if (pheight > 0) {
4332:       switch (coneSize) {
4333:       case 2:
4334:         ct = DM_POLYTOPE_SEGMENT;
4335:         break;
4336:       case 3:
4337:         ct = DM_POLYTOPE_TRIANGLE;
4338:         break;
4339:       case 4:
4340:         ct = DM_POLYTOPE_QUADRILATERAL;
4341:         break;
4342:       default:
4343:         break;
4344:       }
4345:     }
4346:   }
4347:   *pt = ct;
4348:   PetscFunctionReturn(PETSC_SUCCESS);
4349: }

4351: /*@
4352:   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.

4354:   Collective

4356:   Input Parameter:
4357: . dm - The `DMPLEX`

4359:   Level: developer

4361:   Note:
4362:   This function is normally called automatically when a cell type is requested. It creates an
4363:   internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable
4364:   automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype").

4366:   `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()`

4368: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()`
4369: @*/
4370: PetscErrorCode DMPlexComputeCellTypes(DM dm)
4371: {
4372:   DM_Plex *mesh;
4373:   DMLabel  ctLabel;
4374:   PetscInt pStart, pEnd, p;

4376:   PetscFunctionBegin;
4378:   mesh = (DM_Plex *)dm->data;
4379:   PetscCall(DMCreateLabel(dm, "celltype"));
4380:   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
4381:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4382:   PetscCall(PetscFree(mesh->cellTypes));
4383:   PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
4384:   for (p = pStart; p < pEnd; ++p) {
4385:     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4386:     PetscInt       pdepth;

4388:     PetscCall(DMPlexGetPointDepth(dm, p, &pdepth));
4389:     PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct));
4390:     PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p);
4391:     PetscCall(DMLabelSetValue(ctLabel, p, ct));
4392:     mesh->cellTypes[p - pStart].value_as_uint8 = ct;
4393:   }
4394:   PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState));
4395:   PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view"));
4396:   PetscFunctionReturn(PETSC_SUCCESS);
4397: }

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

4402:   Not Collective

4404:   Input Parameters:
4405: + dm        - The `DMPLEX` object
4406: . numPoints - The number of input points for the join
4407: - points    - The input points

4409:   Output Parameters:
4410: + numCoveredPoints - The number of points in the join
4411: - coveredPoints    - The points in the join

4413:   Level: intermediate

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

4418:   Fortran Notes:
4419:   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.

4421: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4422: @*/
4423: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4424: {
4425:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4426:   PetscInt *join[2];
4427:   PetscInt  joinSize, i = 0;
4428:   PetscInt  dof, off, p, c, m;
4429:   PetscInt  maxSupportSize;

4431:   PetscFunctionBegin;
4433:   PetscAssertPointer(points, 3);
4434:   PetscAssertPointer(numCoveredPoints, 4);
4435:   PetscAssertPointer(coveredPoints, 5);
4436:   PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize));
4437:   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0]));
4438:   PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1]));
4439:   /* Copy in support of first point */
4440:   PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof));
4441:   PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off));
4442:   for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize];
4443:   /* Check each successive support */
4444:   for (p = 1; p < numPoints; ++p) {
4445:     PetscInt newJoinSize = 0;

4447:     PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof));
4448:     PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off));
4449:     for (c = 0; c < dof; ++c) {
4450:       const PetscInt point = mesh->supports[off + c];

4452:       for (m = 0; m < joinSize; ++m) {
4453:         if (point == join[i][m]) {
4454:           join[1 - i][newJoinSize++] = point;
4455:           break;
4456:         }
4457:       }
4458:     }
4459:     joinSize = newJoinSize;
4460:     i        = 1 - i;
4461:   }
4462:   *numCoveredPoints = joinSize;
4463:   *coveredPoints    = join[i];
4464:   PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i]));
4465:   PetscFunctionReturn(PETSC_SUCCESS);
4466: }

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

4471:   Not Collective

4473:   Input Parameters:
4474: + dm        - The `DMPLEX` object
4475: . numPoints - The number of input points for the join
4476: - points    - The input points

4478:   Output Parameters:
4479: + numCoveredPoints - The number of points in the join
4480: - coveredPoints    - The points in the join

4482:   Level: intermediate

4484:   Fortran Notes:
4485:   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.

4487: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()`
4488: @*/
4489: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4490: {
4491:   PetscFunctionBegin;
4493:   if (points) PetscAssertPointer(points, 3);
4494:   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
4495:   PetscAssertPointer(coveredPoints, 5);
4496:   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4497:   if (numCoveredPoints) *numCoveredPoints = 0;
4498:   PetscFunctionReturn(PETSC_SUCCESS);
4499: }

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

4504:   Not Collective

4506:   Input Parameters:
4507: + dm        - The `DMPLEX` object
4508: . numPoints - The number of input points for the join
4509: - points    - The input points

4511:   Output Parameters:
4512: + numCoveredPoints - The number of points in the join
4513: - coveredPoints    - The points in the join

4515:   Level: intermediate

4517:   Fortran Notes:
4518:   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.

4520: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()`
4521: @*/
4522: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4523: {
4524:   PetscInt *offsets, **closures;
4525:   PetscInt *join[2];
4526:   PetscInt  depth = 0, maxSize, joinSize = 0, i = 0;
4527:   PetscInt  p, d, c, m, ms;

4529:   PetscFunctionBegin;
4531:   PetscAssertPointer(points, 3);
4532:   PetscAssertPointer(numCoveredPoints, 4);
4533:   PetscAssertPointer(coveredPoints, 5);

4535:   PetscCall(DMPlexGetDepth(dm, &depth));
4536:   PetscCall(PetscCalloc1(numPoints, &closures));
4537:   PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
4538:   PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms));
4539:   maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1;
4540:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]));
4541:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]));

4543:   for (p = 0; p < numPoints; ++p) {
4544:     PetscInt closureSize;

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

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

4552:       PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
4553:       for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) {
4554:         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4555:           offsets[p * (depth + 2) + d + 1] = i;
4556:           break;
4557:         }
4558:       }
4559:       if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i;
4560:     }
4561:     PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize);
4562:   }
4563:   for (d = 0; d < depth + 1; ++d) {
4564:     PetscInt dof;

4566:     /* Copy in support of first point */
4567:     dof = offsets[d + 1] - offsets[d];
4568:     for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2];
4569:     /* Check each successive cone */
4570:     for (p = 1; p < numPoints && joinSize; ++p) {
4571:       PetscInt newJoinSize = 0;

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

4577:         for (m = 0; m < joinSize; ++m) {
4578:           if (point == join[i][m]) {
4579:             join[1 - i][newJoinSize++] = point;
4580:             break;
4581:           }
4582:         }
4583:       }
4584:       joinSize = newJoinSize;
4585:       i        = 1 - i;
4586:     }
4587:     if (joinSize) break;
4588:   }
4589:   *numCoveredPoints = joinSize;
4590:   *coveredPoints    = join[i];
4591:   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]));
4592:   PetscCall(PetscFree(closures));
4593:   PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets));
4594:   PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i]));
4595:   PetscFunctionReturn(PETSC_SUCCESS);
4596: }

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

4601:   Not Collective

4603:   Input Parameters:
4604: + dm        - The `DMPLEX` object
4605: . numPoints - The number of input points for the meet
4606: - points    - The input points

4608:   Output Parameters:
4609: + numCoveringPoints - The number of points in the meet
4610: - coveringPoints    - The points in the meet

4612:   Level: intermediate

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

4617:   Fortran Notes:
4618:   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.

4620: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4621: @*/
4622: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4623: {
4624:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4625:   PetscInt *meet[2];
4626:   PetscInt  meetSize, i = 0;
4627:   PetscInt  dof, off, p, c, m;
4628:   PetscInt  maxConeSize;

4630:   PetscFunctionBegin;
4632:   PetscAssertPointer(points, 3);
4633:   PetscAssertPointer(numCoveringPoints, 4);
4634:   PetscAssertPointer(coveringPoints, 5);
4635:   PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize));
4636:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0]));
4637:   PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1]));
4638:   /* Copy in cone of first point */
4639:   PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof));
4640:   PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off));
4641:   for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize];
4642:   /* Check each successive cone */
4643:   for (p = 1; p < numPoints; ++p) {
4644:     PetscInt newMeetSize = 0;

4646:     PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof));
4647:     PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off));
4648:     for (c = 0; c < dof; ++c) {
4649:       const PetscInt point = mesh->cones[off + c];

4651:       for (m = 0; m < meetSize; ++m) {
4652:         if (point == meet[i][m]) {
4653:           meet[1 - i][newMeetSize++] = point;
4654:           break;
4655:         }
4656:       }
4657:     }
4658:     meetSize = newMeetSize;
4659:     i        = 1 - i;
4660:   }
4661:   *numCoveringPoints = meetSize;
4662:   *coveringPoints    = meet[i];
4663:   PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i]));
4664:   PetscFunctionReturn(PETSC_SUCCESS);
4665: }

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

4670:   Not Collective

4672:   Input Parameters:
4673: + dm        - The `DMPLEX` object
4674: . numPoints - The number of input points for the meet
4675: - points    - The input points

4677:   Output Parameters:
4678: + numCoveredPoints - The number of points in the meet
4679: - coveredPoints    - The points in the meet

4681:   Level: intermediate

4683:   Fortran Notes:
4684:   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.

4686: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()`
4687: @*/
4688: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4689: {
4690:   PetscFunctionBegin;
4692:   if (points) PetscAssertPointer(points, 3);
4693:   if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4);
4694:   PetscAssertPointer(coveredPoints, 5);
4695:   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints));
4696:   if (numCoveredPoints) *numCoveredPoints = 0;
4697:   PetscFunctionReturn(PETSC_SUCCESS);
4698: }

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

4703:   Not Collective

4705:   Input Parameters:
4706: + dm        - The `DMPLEX` object
4707: . numPoints - The number of input points for the meet
4708: - points    - The input points

4710:   Output Parameters:
4711: + numCoveredPoints - The number of points in the meet
4712: - coveredPoints    - The points in the meet

4714:   Level: intermediate

4716:   Fortran Notes:
4717:   The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array.

4719: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()`
4720: @*/
4721: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4722: {
4723:   PetscInt *offsets, **closures;
4724:   PetscInt *meet[2];
4725:   PetscInt  height = 0, maxSize, meetSize = 0, i = 0;
4726:   PetscInt  p, h, c, m, mc;

4728:   PetscFunctionBegin;
4730:   PetscAssertPointer(points, 3);
4731:   PetscAssertPointer(numCoveredPoints, 4);
4732:   PetscAssertPointer(coveredPoints, 5);

4734:   PetscCall(DMPlexGetDepth(dm, &height));
4735:   PetscCall(PetscMalloc1(numPoints, &closures));
4736:   PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
4737:   PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL));
4738:   maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1;
4739:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]));
4740:   PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]));

4742:   for (p = 0; p < numPoints; ++p) {
4743:     PetscInt closureSize;

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

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

4751:       PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd));
4752:       for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) {
4753:         if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) {
4754:           offsets[p * (height + 2) + h + 1] = i;
4755:           break;
4756:         }
4757:       }
4758:       if (i == closureSize) offsets[p * (height + 2) + h + 1] = i;
4759:     }
4760:     PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize);
4761:   }
4762:   for (h = 0; h < height + 1; ++h) {
4763:     PetscInt dof;

4765:     /* Copy in cone of first point */
4766:     dof = offsets[h + 1] - offsets[h];
4767:     for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2];
4768:     /* Check each successive cone */
4769:     for (p = 1; p < numPoints && meetSize; ++p) {
4770:       PetscInt newMeetSize = 0;

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

4776:         for (m = 0; m < meetSize; ++m) {
4777:           if (point == meet[i][m]) {
4778:             meet[1 - i][newMeetSize++] = point;
4779:             break;
4780:           }
4781:         }
4782:       }
4783:       meetSize = newMeetSize;
4784:       i        = 1 - i;
4785:     }
4786:     if (meetSize) break;
4787:   }
4788:   *numCoveredPoints = meetSize;
4789:   *coveredPoints    = meet[i];
4790:   for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]));
4791:   PetscCall(PetscFree(closures));
4792:   PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets));
4793:   PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i]));
4794:   PetscFunctionReturn(PETSC_SUCCESS);
4795: }

4797: /*@C
4798:   DMPlexEqual - Determine if two `DM` have the same topology

4800:   Not Collective

4802:   Input Parameters:
4803: + dmA - A `DMPLEX` object
4804: - dmB - A `DMPLEX` object

4806:   Output Parameter:
4807: . equal - `PETSC_TRUE` if the topologies are identical

4809:   Level: intermediate

4811:   Note:
4812:   We are not solving graph isomorphism, so we do not permute.

4814: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
4815: @*/
4816: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
4817: {
4818:   PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p;

4820:   PetscFunctionBegin;
4823:   PetscAssertPointer(equal, 3);

4825:   *equal = PETSC_FALSE;
4826:   PetscCall(DMPlexGetDepth(dmA, &depth));
4827:   PetscCall(DMPlexGetDepth(dmB, &depthB));
4828:   if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS);
4829:   PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd));
4830:   PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB));
4831:   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS);
4832:   for (p = pStart; p < pEnd; ++p) {
4833:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
4834:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

4836:     PetscCall(DMPlexGetConeSize(dmA, p, &coneSize));
4837:     PetscCall(DMPlexGetCone(dmA, p, &cone));
4838:     PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt));
4839:     PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB));
4840:     PetscCall(DMPlexGetCone(dmB, p, &coneB));
4841:     PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB));
4842:     if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS);
4843:     for (c = 0; c < coneSize; ++c) {
4844:       if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS);
4845:       if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS);
4846:     }
4847:     PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize));
4848:     PetscCall(DMPlexGetSupport(dmA, p, &support));
4849:     PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB));
4850:     PetscCall(DMPlexGetSupport(dmB, p, &supportB));
4851:     if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS);
4852:     for (s = 0; s < supportSize; ++s) {
4853:       if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS);
4854:     }
4855:   }
4856:   *equal = PETSC_TRUE;
4857:   PetscFunctionReturn(PETSC_SUCCESS);
4858: }

4860: /*@C
4861:   DMPlexGetNumFaceVertices - Returns the number of vertices on a face

4863:   Not Collective

4865:   Input Parameters:
4866: + dm         - The `DMPLEX`
4867: . cellDim    - The cell dimension
4868: - numCorners - The number of vertices on a cell

4870:   Output Parameter:
4871: . numFaceVertices - The number of vertices on a face

4873:   Level: developer

4875:   Note:
4876:   Of course this can only work for a restricted set of symmetric shapes

4878: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()`
4879: @*/
4880: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4881: {
4882:   MPI_Comm comm;

4884:   PetscFunctionBegin;
4885:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4886:   PetscAssertPointer(numFaceVertices, 4);
4887:   switch (cellDim) {
4888:   case 0:
4889:     *numFaceVertices = 0;
4890:     break;
4891:   case 1:
4892:     *numFaceVertices = 1;
4893:     break;
4894:   case 2:
4895:     switch (numCorners) {
4896:     case 3:                 /* triangle */
4897:       *numFaceVertices = 2; /* Edge has 2 vertices */
4898:       break;
4899:     case 4:                 /* quadrilateral */
4900:       *numFaceVertices = 2; /* Edge has 2 vertices */
4901:       break;
4902:     case 6:                 /* quadratic triangle, tri and quad cohesive Lagrange cells */
4903:       *numFaceVertices = 3; /* Edge has 3 vertices */
4904:       break;
4905:     case 9:                 /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
4906:       *numFaceVertices = 3; /* Edge has 3 vertices */
4907:       break;
4908:     default:
4909:       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4910:     }
4911:     break;
4912:   case 3:
4913:     switch (numCorners) {
4914:     case 4:                 /* tetradehdron */
4915:       *numFaceVertices = 3; /* Face has 3 vertices */
4916:       break;
4917:     case 6:                 /* tet cohesive cells */
4918:       *numFaceVertices = 4; /* Face has 4 vertices */
4919:       break;
4920:     case 8:                 /* hexahedron */
4921:       *numFaceVertices = 4; /* Face has 4 vertices */
4922:       break;
4923:     case 9:                 /* tet cohesive Lagrange cells */
4924:       *numFaceVertices = 6; /* Face has 6 vertices */
4925:       break;
4926:     case 10:                /* quadratic tetrahedron */
4927:       *numFaceVertices = 6; /* Face has 6 vertices */
4928:       break;
4929:     case 12:                /* hex cohesive Lagrange cells */
4930:       *numFaceVertices = 6; /* Face has 6 vertices */
4931:       break;
4932:     case 18:                /* quadratic tet cohesive Lagrange cells */
4933:       *numFaceVertices = 6; /* Face has 6 vertices */
4934:       break;
4935:     case 27:                /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
4936:       *numFaceVertices = 9; /* Face has 9 vertices */
4937:       break;
4938:     default:
4939:       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim);
4940:     }
4941:     break;
4942:   default:
4943:     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim);
4944:   }
4945:   PetscFunctionReturn(PETSC_SUCCESS);
4946: }

4948: /*@
4949:   DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point

4951:   Not Collective

4953:   Input Parameter:
4954: . dm - The `DMPLEX` object

4956:   Output Parameter:
4957: . depthLabel - The `DMLabel` recording point depth

4959:   Level: developer

4961: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`,
4962: @*/
4963: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4964: {
4965:   PetscFunctionBegin;
4967:   PetscAssertPointer(depthLabel, 2);
4968:   *depthLabel = dm->depthLabel;
4969:   PetscFunctionReturn(PETSC_SUCCESS);
4970: }

4972: /*@
4973:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

4975:   Not Collective

4977:   Input Parameter:
4978: . dm - The `DMPLEX` object

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

4983:   Level: developer

4985:   Notes:
4986:   This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`.

4988:   The point depth is described more in detail in `DMPlexGetDepthStratum()`.

4990:   An empty mesh gives -1.

4992: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`
4993: @*/
4994: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4995: {
4996:   DM_Plex *mesh = (DM_Plex *)dm->data;
4997:   DMLabel  label;
4998:   PetscInt d = 0;

5000:   PetscFunctionBegin;
5002:   PetscAssertPointer(depth, 2);
5003:   if (mesh->tr) {
5004:     PetscCall(DMPlexTransformGetDepth(mesh->tr, depth));
5005:   } else {
5006:     PetscCall(DMPlexGetDepthLabel(dm, &label));
5007:     if (label) PetscCall(DMLabelGetNumValues(label, &d));
5008:     *depth = d - 1;
5009:   }
5010:   PetscFunctionReturn(PETSC_SUCCESS);
5011: }

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

5016:   Not Collective

5018:   Input Parameters:
5019: + dm    - The `DMPLEX` object
5020: - depth - The requested depth

5022:   Output Parameters:
5023: + start - The first point at this `depth`
5024: - end   - One beyond the last point at this `depth`

5026:   Level: developer

5028:   Notes:
5029:   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
5030:   often "vertices".  If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next
5031:   higher dimension, e.g., "edges".

5033: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()`
5034: @*/
5035: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end)
5036: {
5037:   DM_Plex *mesh = (DM_Plex *)dm->data;
5038:   DMLabel  label;
5039:   PetscInt pStart, pEnd;

5041:   PetscFunctionBegin;
5043:   if (start) {
5044:     PetscAssertPointer(start, 3);
5045:     *start = 0;
5046:   }
5047:   if (end) {
5048:     PetscAssertPointer(end, 4);
5049:     *end = 0;
5050:   }
5051:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5052:   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5053:   if (depth < 0) {
5054:     if (start) *start = pStart;
5055:     if (end) *end = pEnd;
5056:     PetscFunctionReturn(PETSC_SUCCESS);
5057:   }
5058:   if (mesh->tr) {
5059:     PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end));
5060:   } else {
5061:     PetscCall(DMPlexGetDepthLabel(dm, &label));
5062:     PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5063:     PetscCall(DMLabelGetStratumBounds(label, depth, start, end));
5064:   }
5065:   PetscFunctionReturn(PETSC_SUCCESS);
5066: }

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

5071:   Not Collective

5073:   Input Parameters:
5074: + dm     - The `DMPLEX` object
5075: - height - The requested height

5077:   Output Parameters:
5078: + start - The first point at this `height`
5079: - end   - One beyond the last point at this `height`

5081:   Level: developer

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

5088: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5089: @*/
5090: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end)
5091: {
5092:   DMLabel  label;
5093:   PetscInt depth, pStart, pEnd;

5095:   PetscFunctionBegin;
5097:   if (start) {
5098:     PetscAssertPointer(start, 3);
5099:     *start = 0;
5100:   }
5101:   if (end) {
5102:     PetscAssertPointer(end, 4);
5103:     *end = 0;
5104:   }
5105:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5106:   if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS);
5107:   if (height < 0) {
5108:     if (start) *start = pStart;
5109:     if (end) *end = pEnd;
5110:     PetscFunctionReturn(PETSC_SUCCESS);
5111:   }
5112:   PetscCall(DMPlexGetDepthLabel(dm, &label));
5113:   if (label) PetscCall(DMLabelGetNumValues(label, &depth));
5114:   else PetscCall(DMGetDimension(dm, &depth));
5115:   PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed");
5116:   PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end));
5117:   PetscFunctionReturn(PETSC_SUCCESS);
5118: }

5120: /*@
5121:   DMPlexGetPointDepth - Get the `depth` of a given point

5123:   Not Collective

5125:   Input Parameters:
5126: + dm    - The `DMPLEX` object
5127: - point - The point

5129:   Output Parameter:
5130: . depth - The depth of the `point`

5132:   Level: intermediate

5134: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()`
5135: @*/
5136: PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
5137: {
5138:   PetscFunctionBegin;
5140:   PetscAssertPointer(depth, 3);
5141:   PetscCall(DMLabelGetValue(dm->depthLabel, point, depth));
5142:   PetscFunctionReturn(PETSC_SUCCESS);
5143: }

5145: /*@
5146:   DMPlexGetPointHeight - Get the `height` of a given point

5148:   Not Collective

5150:   Input Parameters:
5151: + dm    - The `DMPLEX` object
5152: - point - The point

5154:   Output Parameter:
5155: . height - The height of the `point`

5157:   Level: intermediate

5159: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()`
5160: @*/
5161: PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
5162: {
5163:   PetscInt n, pDepth;

5165:   PetscFunctionBegin;
5167:   PetscAssertPointer(height, 3);
5168:   PetscCall(DMLabelGetNumValues(dm->depthLabel, &n));
5169:   PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth));
5170:   *height = n - 1 - pDepth; /* DAG depth is n-1 */
5171:   PetscFunctionReturn(PETSC_SUCCESS);
5172: }

5174: /*@
5175:   DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell

5177:   Not Collective

5179:   Input Parameter:
5180: . dm - The `DMPLEX` object

5182:   Output Parameter:
5183: . celltypeLabel - The `DMLabel` recording cell polytope type

5185:   Level: developer

5187:   Note:
5188:   This function will trigger automatica computation of cell types. This can be disabled by calling
5189:   `DMCreateLabel`(dm, "celltype") beforehand.

5191: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()`
5192: @*/
5193: PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
5194: {
5195:   PetscFunctionBegin;
5197:   PetscAssertPointer(celltypeLabel, 2);
5198:   if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm));
5199:   *celltypeLabel = dm->celltypeLabel;
5200:   PetscFunctionReturn(PETSC_SUCCESS);
5201: }

5203: /*@
5204:   DMPlexGetCellType - Get the polytope type of a given cell

5206:   Not Collective

5208:   Input Parameters:
5209: + dm   - The `DMPLEX` object
5210: - cell - The cell

5212:   Output Parameter:
5213: . celltype - The polytope type of the cell

5215:   Level: intermediate

5217: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`
5218: @*/
5219: PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
5220: {
5221:   DM_Plex *mesh = (DM_Plex *)dm->data;
5222:   DMLabel  label;
5223:   PetscInt ct;

5225:   PetscFunctionBegin;
5227:   PetscAssertPointer(celltype, 3);
5228:   if (mesh->tr) {
5229:     PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype));
5230:   } else {
5231:     PetscInt pStart, pEnd;

5233:     PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL));
5234:     if (!mesh->cellTypes) { /* XXX remove? optimize? */
5235:       PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd));
5236:       PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5237:       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5238:       for (PetscInt p = pStart; p < pEnd; p++) {
5239:         PetscCall(DMLabelGetValue(label, p, &ct));
5240:         mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct;
5241:       }
5242:     }
5243:     *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8;
5244:     if (PetscDefined(USE_DEBUG)) {
5245:       PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5246:       PetscCall(DMLabelGetValue(label, cell, &ct));
5247:       PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell);
5248:       PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct);
5249:     }
5250:   }
5251:   PetscFunctionReturn(PETSC_SUCCESS);
5252: }

5254: /*@
5255:   DMPlexSetCellType - Set the polytope type of a given cell

5257:   Not Collective

5259:   Input Parameters:
5260: + dm       - The `DMPLEX` object
5261: . cell     - The cell
5262: - celltype - The polytope type of the cell

5264:   Level: advanced

5266:   Note:
5267:   By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function
5268:   is executed. This function will override the computed type. However, if automatic classification will not succeed
5269:   and a user wants to manually specify all types, the classification must be disabled by calling
5270:   DMCreateLabel(dm, "celltype") before getting or setting any cell types.

5272: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()`
5273: @*/
5274: PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
5275: {
5276:   DM_Plex *mesh = (DM_Plex *)dm->data;
5277:   DMLabel  label;
5278:   PetscInt pStart, pEnd;

5280:   PetscFunctionBegin;
5282:   PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd));
5283:   PetscCall(DMPlexGetCellTypeLabel(dm, &label));
5284:   PetscCall(DMLabelSetValue(label, cell, celltype));
5285:   if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes));
5286:   mesh->cellTypes[cell - pStart].value_as_uint8 = celltype;
5287:   PetscFunctionReturn(PETSC_SUCCESS);
5288: }

5290: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
5291: {
5292:   PetscSection section, s;
5293:   Mat          m;
5294:   PetscInt     maxHeight;
5295:   const char  *prefix;

5297:   PetscFunctionBegin;
5298:   PetscCall(DMClone(dm, cdm));
5299:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
5300:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
5301:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
5302:   PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight));
5303:   PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight));
5304:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
5305:   PetscCall(DMSetLocalSection(*cdm, section));
5306:   PetscCall(PetscSectionDestroy(&section));
5307:   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
5308:   PetscCall(MatCreate(PETSC_COMM_SELF, &m));
5309:   PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL));
5310:   PetscCall(PetscSectionDestroy(&s));
5311:   PetscCall(MatDestroy(&m));

5313:   PetscCall(DMSetNumFields(*cdm, 1));
5314:   PetscCall(DMCreateDS(*cdm));
5315:   (*cdm)->cloneOpts = PETSC_TRUE;
5316:   if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm));
5317:   PetscFunctionReturn(PETSC_SUCCESS);
5318: }

5320: PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5321: {
5322:   Vec coordsLocal, cellCoordsLocal;
5323:   DM  coordsDM, cellCoordsDM;

5325:   PetscFunctionBegin;
5326:   *field = NULL;
5327:   PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal));
5328:   PetscCall(DMGetCoordinateDM(dm, &coordsDM));
5329:   PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal));
5330:   PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM));
5331:   if (coordsLocal && coordsDM) {
5332:     if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field));
5333:     else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field));
5334:   }
5335:   PetscFunctionReturn(PETSC_SUCCESS);
5336: }

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

5341:   Not Collective

5343:   Input Parameter:
5344: . dm - The `DMPLEX` object

5346:   Output Parameter:
5347: . section - The `PetscSection` object

5349:   Level: developer

5351: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection`
5352: @*/
5353: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5354: {
5355:   DM_Plex *mesh = (DM_Plex *)dm->data;

5357:   PetscFunctionBegin;
5359:   if (section) *section = mesh->coneSection;
5360:   PetscFunctionReturn(PETSC_SUCCESS);
5361: }

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

5366:   Not Collective

5368:   Input Parameter:
5369: . dm - The `DMPLEX` object

5371:   Output Parameter:
5372: . section - The `PetscSection` object

5374:   Level: developer

5376: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection`
5377: @*/
5378: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5379: {
5380:   DM_Plex *mesh = (DM_Plex *)dm->data;

5382:   PetscFunctionBegin;
5384:   if (section) *section = mesh->supportSection;
5385:   PetscFunctionReturn(PETSC_SUCCESS);
5386: }

5388: /*@C
5389:   DMPlexGetCones - Return cone data

5391:   Not Collective

5393:   Input Parameter:
5394: . dm - The `DMPLEX` object

5396:   Output Parameter:
5397: . cones - The cone for each point

5399:   Level: developer

5401: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`
5402: @*/
5403: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5404: {
5405:   DM_Plex *mesh = (DM_Plex *)dm->data;

5407:   PetscFunctionBegin;
5409:   if (cones) *cones = mesh->cones;
5410:   PetscFunctionReturn(PETSC_SUCCESS);
5411: }

5413: /*@C
5414:   DMPlexGetConeOrientations - Return cone orientation data

5416:   Not Collective

5418:   Input Parameter:
5419: . dm - The `DMPLEX` object

5421:   Output Parameter:
5422: . coneOrientations - The array of cone orientations for all points

5424:   Level: developer

5426:   Notes:
5427:   The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`.

5429:   The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`.

5431: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection`
5432: @*/
5433: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5434: {
5435:   DM_Plex *mesh = (DM_Plex *)dm->data;

5437:   PetscFunctionBegin;
5439:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5440:   PetscFunctionReturn(PETSC_SUCCESS);
5441: }

5443: /******************************** FEM Support **********************************/

5445: PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS)
5446: {
5447:   PetscInt depth;

5449:   PetscFunctionBegin;
5450:   PetscCall(DMPlexGetDepth(plex, &depth));
5451:   PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS));
5452:   if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS));
5453:   PetscFunctionReturn(PETSC_SUCCESS);
5454: }

5456: /*
5457:  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
5458:  representing a line in the section.
5459: */
5460: static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k)
5461: {
5462:   PetscFunctionBeginHot;
5463:   PetscCall(PetscSectionGetFieldComponents(section, field, Nc));
5464:   if (line < 0) {
5465:     *k  = 0;
5466:     *Nc = 0;
5467:   } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */
5468:     *k = 1;
5469:   } else { /* Assume the full interpolated mesh is in the chart; lines in particular */
5470:     /* An order k SEM disc has k-1 dofs on an edge */
5471:     PetscCall(PetscSectionGetFieldDof(section, line, field, k));
5472:     *k = *k / *Nc + 1;
5473:   }
5474:   PetscFunctionReturn(PETSC_SUCCESS);
5475: }

5477: /*@

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

5483:   Input Parameters:
5484: + dm      - The `DM`
5485: . point   - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE`
5486: - section - The `PetscSection` to reorder, or `NULL` for the default section

5488:   Example:
5489:   A typical interpolated single-quad mesh might order points as
5490: .vb
5491:   [c0, v1, v2, v3, v4, e5, e6, e7, e8]

5493:   v4 -- e6 -- v3
5494:   |           |
5495:   e7    c0    e8
5496:   |           |
5497:   v1 -- e5 -- v2
5498: .ve

5500:   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5501:   dofs in the order of points, e.g.,
5502: .vb
5503:     c0 -> [0,1,2,3]
5504:     v1 -> [4]
5505:     ...
5506:     e5 -> [8, 9]
5507: .ve

5509:   which corresponds to the dofs
5510: .vb
5511:     6   10  11  7
5512:     13  2   3   15
5513:     12  0   1   14
5514:     4   8   9   5
5515: .ve

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

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

5527:   Level: developer

5529:   Notes:
5530:   The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5531:   degree of the basis.

5533:   This is required to run with libCEED.

5535: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()`
5536: @*/
5537: PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5538: {
5539:   DMLabel   label;
5540:   PetscInt  dim, depth = -1, eStart = -1, Nf;
5541:   PetscBool vertexchart;

5543:   PetscFunctionBegin;
5544:   PetscCall(DMGetDimension(dm, &dim));
5545:   if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS);
5546:   if (point < 0) {
5547:     PetscInt sStart, sEnd;

5549:     PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd));
5550:     point = sEnd - sStart ? sStart : point;
5551:   }
5552:   PetscCall(DMPlexGetDepthLabel(dm, &label));
5553:   if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth));
5554:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
5555:   if (depth == 1) {
5556:     eStart = point;
5557:   } else if (depth == dim) {
5558:     const PetscInt *cone;

5560:     PetscCall(DMPlexGetCone(dm, point, &cone));
5561:     if (dim == 2) eStart = cone[0];
5562:     else if (dim == 3) {
5563:       const PetscInt *cone2;
5564:       PetscCall(DMPlexGetCone(dm, cone[0], &cone2));
5565:       eStart = cone2[0];
5566:     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim);
5567:   } else PetscCheck(depth < 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim);
5568:   { /* Determine whether the chart covers all points or just vertices. */
5569:     PetscInt pStart, pEnd, cStart, cEnd;
5570:     PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd));
5571:     PetscCall(PetscSectionGetChart(section, &cStart, &cEnd));
5572:     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE;      /* Only vertices are in the chart */
5573:     else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */
5574:     else vertexchart = PETSC_TRUE;                                       /* Some interpolated points are not in chart; assume dofs only at cells and vertices */
5575:   }
5576:   PetscCall(PetscSectionGetNumFields(section, &Nf));
5577:   for (PetscInt d = 1; d <= dim; d++) {
5578:     PetscInt  k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5579:     PetscInt *perm;

5581:     for (f = 0; f < Nf; ++f) {
5582:       PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5583:       size += PetscPowInt(k + 1, d) * Nc;
5584:     }
5585:     PetscCall(PetscMalloc1(size, &perm));
5586:     for (f = 0; f < Nf; ++f) {
5587:       switch (d) {
5588:       case 1:
5589:         PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5590:         /*
5591:          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5592:          We want              [ vtx0; edge of length k-1; vtx1 ]
5593:          */
5594:         for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset;
5595:         for (i = 0; i < k - 1; i++)
5596:           for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset;
5597:         for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset;
5598:         foffset = offset;
5599:         break;
5600:       case 2:
5601:         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
5602:         PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5603:         /* The SEM order is

5605:          v_lb, {e_b}, v_rb,
5606:          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
5607:          v_lt, reverse {e_t}, v_rt
5608:          */
5609:         {
5610:           const PetscInt of   = 0;
5611:           const PetscInt oeb  = of + PetscSqr(k - 1);
5612:           const PetscInt oer  = oeb + (k - 1);
5613:           const PetscInt oet  = oer + (k - 1);
5614:           const PetscInt oel  = oet + (k - 1);
5615:           const PetscInt ovlb = oel + (k - 1);
5616:           const PetscInt ovrb = ovlb + 1;
5617:           const PetscInt ovrt = ovrb + 1;
5618:           const PetscInt ovlt = ovrt + 1;
5619:           PetscInt       o;

5621:           /* bottom */
5622:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset;
5623:           for (o = oeb; o < oer; ++o)
5624:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5625:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset;
5626:           /* middle */
5627:           for (i = 0; i < k - 1; ++i) {
5628:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset;
5629:             for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o)
5630:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5631:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset;
5632:           }
5633:           /* top */
5634:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset;
5635:           for (o = oel - 1; o >= oet; --o)
5636:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5637:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset;
5638:           foffset = offset;
5639:         }
5640:         break;
5641:       case 3:
5642:         /* The original hex closure is

5644:          {c,
5645:          f_b, f_t, f_f, f_b, f_r, f_l,
5646:          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
5647:          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
5648:          */
5649:         PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k));
5650:         /* The SEM order is
5651:          Bottom Slice
5652:          v_blf, {e^{(k-1)-n}_bf}, v_brf,
5653:          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
5654:          v_blb, {e_bb}, v_brb,

5656:          Middle Slice (j)
5657:          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
5658:          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
5659:          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,

5661:          Top Slice
5662:          v_tlf, {e_tf}, v_trf,
5663:          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
5664:          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
5665:          */
5666:         {
5667:           const PetscInt oc    = 0;
5668:           const PetscInt ofb   = oc + PetscSqr(k - 1) * (k - 1);
5669:           const PetscInt oft   = ofb + PetscSqr(k - 1);
5670:           const PetscInt off   = oft + PetscSqr(k - 1);
5671:           const PetscInt ofk   = off + PetscSqr(k - 1);
5672:           const PetscInt ofr   = ofk + PetscSqr(k - 1);
5673:           const PetscInt ofl   = ofr + PetscSqr(k - 1);
5674:           const PetscInt oebl  = ofl + PetscSqr(k - 1);
5675:           const PetscInt oebb  = oebl + (k - 1);
5676:           const PetscInt oebr  = oebb + (k - 1);
5677:           const PetscInt oebf  = oebr + (k - 1);
5678:           const PetscInt oetf  = oebf + (k - 1);
5679:           const PetscInt oetr  = oetf + (k - 1);
5680:           const PetscInt oetb  = oetr + (k - 1);
5681:           const PetscInt oetl  = oetb + (k - 1);
5682:           const PetscInt oerf  = oetl + (k - 1);
5683:           const PetscInt oelf  = oerf + (k - 1);
5684:           const PetscInt oelb  = oelf + (k - 1);
5685:           const PetscInt oerb  = oelb + (k - 1);
5686:           const PetscInt ovblf = oerb + (k - 1);
5687:           const PetscInt ovblb = ovblf + 1;
5688:           const PetscInt ovbrb = ovblb + 1;
5689:           const PetscInt ovbrf = ovbrb + 1;
5690:           const PetscInt ovtlf = ovbrf + 1;
5691:           const PetscInt ovtrf = ovtlf + 1;
5692:           const PetscInt ovtrb = ovtrf + 1;
5693:           const PetscInt ovtlb = ovtrb + 1;
5694:           PetscInt       o, n;

5696:           /* Bottom Slice */
5697:           /*   bottom */
5698:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset;
5699:           for (o = oetf - 1; o >= oebf; --o)
5700:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5701:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset;
5702:           /*   middle */
5703:           for (i = 0; i < k - 1; ++i) {
5704:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset;
5705:             for (n = 0; n < k - 1; ++n) {
5706:               o = ofb + n * (k - 1) + i;
5707:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5708:             }
5709:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset;
5710:           }
5711:           /*   top */
5712:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset;
5713:           for (o = oebb; o < oebr; ++o)
5714:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5715:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset;

5717:           /* Middle Slice */
5718:           for (j = 0; j < k - 1; ++j) {
5719:             /*   bottom */
5720:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset;
5721:             for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o)
5722:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5723:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset;
5724:             /*   middle */
5725:             for (i = 0; i < k - 1; ++i) {
5726:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset;
5727:               for (n = 0; n < k - 1; ++n)
5728:                 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset;
5729:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset;
5730:             }
5731:             /*   top */
5732:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset;
5733:             for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o)
5734:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5735:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset;
5736:           }

5738:           /* Top Slice */
5739:           /*   bottom */
5740:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset;
5741:           for (o = oetf; o < oetr; ++o)
5742:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5743:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset;
5744:           /*   middle */
5745:           for (i = 0; i < k - 1; ++i) {
5746:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset;
5747:             for (n = 0; n < k - 1; ++n)
5748:               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset;
5749:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset;
5750:           }
5751:           /*   top */
5752:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset;
5753:           for (o = oetl - 1; o >= oetb; --o)
5754:             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset;
5755:           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset;

5757:           foffset = offset;
5758:         }
5759:         break;
5760:       default:
5761:         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d);
5762:       }
5763:     }
5764:     PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size);
5765:     /* Check permutation */
5766:     {
5767:       PetscInt *check;

5769:       PetscCall(PetscMalloc1(size, &check));
5770:       for (i = 0; i < size; ++i) {
5771:         check[i] = -1;
5772:         PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]);
5773:       }
5774:       for (i = 0; i < size; ++i) check[perm[i]] = i;
5775:       for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);
5776:       PetscCall(PetscFree(check));
5777:     }
5778:     PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm));
5779:     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
5780:       PetscInt *loc_perm;
5781:       PetscCall(PetscMalloc1(size * 2, &loc_perm));
5782:       for (PetscInt i = 0; i < size; i++) {
5783:         loc_perm[i]        = perm[i];
5784:         loc_perm[size + i] = size + perm[i];
5785:       }
5786:       PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm));
5787:     }
5788:   }
5789:   PetscFunctionReturn(PETSC_SUCCESS);
5790: }

5792: PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5793: {
5794:   PetscDS  prob;
5795:   PetscInt depth, Nf, h;
5796:   DMLabel  label;

5798:   PetscFunctionBeginHot;
5799:   PetscCall(DMGetDS(dm, &prob));
5800:   Nf      = prob->Nf;
5801:   label   = dm->depthLabel;
5802:   *dspace = NULL;
5803:   if (field < Nf) {
5804:     PetscObject disc = prob->disc[field];

5806:     if (disc->classid == PETSCFE_CLASSID) {
5807:       PetscDualSpace dsp;

5809:       PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp));
5810:       PetscCall(DMLabelGetNumValues(label, &depth));
5811:       PetscCall(DMLabelGetValue(label, point, &h));
5812:       h = depth - 1 - h;
5813:       if (h) {
5814:         PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace));
5815:       } else {
5816:         *dspace = dsp;
5817:       }
5818:     }
5819:   }
5820:   PetscFunctionReturn(PETSC_SUCCESS);
5821: }

5823: static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5824: {
5825:   PetscScalar       *array;
5826:   const PetscScalar *vArray;
5827:   const PetscInt    *cone, *coneO;
5828:   PetscInt           pStart, pEnd, p, numPoints, size = 0, offset = 0;

5830:   PetscFunctionBeginHot;
5831:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
5832:   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
5833:   PetscCall(DMPlexGetCone(dm, point, &cone));
5834:   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
5835:   if (!values || !*values) {
5836:     if ((point >= pStart) && (point < pEnd)) {
5837:       PetscInt dof;

5839:       PetscCall(PetscSectionGetDof(section, point, &dof));
5840:       size += dof;
5841:     }
5842:     for (p = 0; p < numPoints; ++p) {
5843:       const PetscInt cp = cone[p];
5844:       PetscInt       dof;

5846:       if ((cp < pStart) || (cp >= pEnd)) continue;
5847:       PetscCall(PetscSectionGetDof(section, cp, &dof));
5848:       size += dof;
5849:     }
5850:     if (!values) {
5851:       if (csize) *csize = size;
5852:       PetscFunctionReturn(PETSC_SUCCESS);
5853:     }
5854:     PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array));
5855:   } else {
5856:     array = *values;
5857:   }
5858:   size = 0;
5859:   PetscCall(VecGetArrayRead(v, &vArray));
5860:   if ((point >= pStart) && (point < pEnd)) {
5861:     PetscInt           dof, off, d;
5862:     const PetscScalar *varr;

5864:     PetscCall(PetscSectionGetDof(section, point, &dof));
5865:     PetscCall(PetscSectionGetOffset(section, point, &off));
5866:     varr = &vArray[off];
5867:     for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
5868:     size += dof;
5869:   }
5870:   for (p = 0; p < numPoints; ++p) {
5871:     const PetscInt     cp = cone[p];
5872:     PetscInt           o  = coneO[p];
5873:     PetscInt           dof, off, d;
5874:     const PetscScalar *varr;

5876:     if ((cp < pStart) || (cp >= pEnd)) continue;
5877:     PetscCall(PetscSectionGetDof(section, cp, &dof));
5878:     PetscCall(PetscSectionGetOffset(section, cp, &off));
5879:     varr = &vArray[off];
5880:     if (o >= 0) {
5881:       for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d];
5882:     } else {
5883:       for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d];
5884:     }
5885:     size += dof;
5886:   }
5887:   PetscCall(VecRestoreArrayRead(v, &vArray));
5888:   if (!*values) {
5889:     if (csize) *csize = size;
5890:     *values = array;
5891:   } else {
5892:     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
5893:     *csize = size;
5894:   }
5895:   PetscFunctionReturn(PETSC_SUCCESS);
5896: }

5898: /* Compress out points not in the section */
5899: static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
5900: {
5901:   const PetscInt np = *numPoints;
5902:   PetscInt       pStart, pEnd, p, q;

5904:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
5905:   for (p = 0, q = 0; p < np; ++p) {
5906:     const PetscInt r = points[p * 2];
5907:     if ((r >= pStart) && (r < pEnd)) {
5908:       points[q * 2]     = r;
5909:       points[q * 2 + 1] = points[p * 2 + 1];
5910:       ++q;
5911:     }
5912:   }
5913:   *numPoints = q;
5914:   return PETSC_SUCCESS;
5915: }

5917: /* Compressed closure does not apply closure permutation */
5918: PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5919: {
5920:   const PetscInt *cla = NULL;
5921:   PetscInt        np, *pts = NULL;

5923:   PetscFunctionBeginHot;
5924:   PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints));
5925:   if (!ornt && *clPoints) {
5926:     PetscInt dof, off;

5928:     PetscCall(PetscSectionGetDof(*clSec, point, &dof));
5929:     PetscCall(PetscSectionGetOffset(*clSec, point, &off));
5930:     PetscCall(ISGetIndices(*clPoints, &cla));
5931:     np  = dof / 2;
5932:     pts = (PetscInt *)&cla[off];
5933:   } else {
5934:     PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts));
5935:     PetscCall(CompressPoints_Private(section, &np, pts));
5936:   }
5937:   *numPoints = np;
5938:   *points    = pts;
5939:   *clp       = cla;
5940:   PetscFunctionReturn(PETSC_SUCCESS);
5941: }

5943: PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5944: {
5945:   PetscFunctionBeginHot;
5946:   if (!*clPoints) {
5947:     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points));
5948:   } else {
5949:     PetscCall(ISRestoreIndices(*clPoints, clp));
5950:   }
5951:   *numPoints = 0;
5952:   *points    = NULL;
5953:   *clSec     = NULL;
5954:   *clPoints  = NULL;
5955:   *clp       = NULL;
5956:   PetscFunctionReturn(PETSC_SUCCESS);
5957: }

5959: static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
5960: {
5961:   PetscInt            offset = 0, p;
5962:   const PetscInt    **perms  = NULL;
5963:   const PetscScalar **flips  = NULL;

5965:   PetscFunctionBeginHot;
5966:   *size = 0;
5967:   PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
5968:   for (p = 0; p < numPoints; p++) {
5969:     const PetscInt     point = points[2 * p];
5970:     const PetscInt    *perm  = perms ? perms[p] : NULL;
5971:     const PetscScalar *flip  = flips ? flips[p] : NULL;
5972:     PetscInt           dof, off, d;
5973:     const PetscScalar *varr;

5975:     PetscCall(PetscSectionGetDof(section, point, &dof));
5976:     PetscCall(PetscSectionGetOffset(section, point, &off));
5977:     varr = &vArray[off];
5978:     if (clperm) {
5979:       if (perm) {
5980:         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d];
5981:       } else {
5982:         for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d];
5983:       }
5984:       if (flip) {
5985:         for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d];
5986:       }
5987:     } else {
5988:       if (perm) {
5989:         for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d];
5990:       } else {
5991:         for (d = 0; d < dof; d++) array[offset + d] = varr[d];
5992:       }
5993:       if (flip) {
5994:         for (d = 0; d < dof; d++) array[offset + d] *= flip[d];
5995:       }
5996:     }
5997:     offset += dof;
5998:   }
5999:   PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
6000:   *size = offset;
6001:   PetscFunctionReturn(PETSC_SUCCESS);
6002: }

6004: 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[])
6005: {
6006:   PetscInt offset = 0, f;

6008:   PetscFunctionBeginHot;
6009:   *size = 0;
6010:   for (f = 0; f < numFields; ++f) {
6011:     PetscInt            p;
6012:     const PetscInt    **perms = NULL;
6013:     const PetscScalar **flips = NULL;

6015:     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6016:     for (p = 0; p < numPoints; p++) {
6017:       const PetscInt     point = points[2 * p];
6018:       PetscInt           fdof, foff, b;
6019:       const PetscScalar *varr;
6020:       const PetscInt    *perm = perms ? perms[p] : NULL;
6021:       const PetscScalar *flip = flips ? flips[p] : NULL;

6023:       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6024:       PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6025:       varr = &vArray[foff];
6026:       if (clperm) {
6027:         if (perm) {
6028:           for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b];
6029:         } else {
6030:           for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b];
6031:         }
6032:         if (flip) {
6033:           for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b];
6034:         }
6035:       } else {
6036:         if (perm) {
6037:           for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b];
6038:         } else {
6039:           for (b = 0; b < fdof; b++) array[offset + b] = varr[b];
6040:         }
6041:         if (flip) {
6042:           for (b = 0; b < fdof; b++) array[offset + b] *= flip[b];
6043:         }
6044:       }
6045:       offset += fdof;
6046:     }
6047:     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6048:   }
6049:   *size = offset;
6050:   PetscFunctionReturn(PETSC_SUCCESS);
6051: }

6053: PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[])
6054: {
6055:   PetscSection    clSection;
6056:   IS              clPoints;
6057:   PetscInt       *points = NULL;
6058:   const PetscInt *clp, *perm = NULL;
6059:   PetscInt        depth, numFields, numPoints, asize;

6061:   PetscFunctionBeginHot;
6063:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6066:   PetscCall(DMPlexGetDepth(dm, &depth));
6067:   PetscCall(PetscSectionGetNumFields(section, &numFields));
6068:   if (depth == 1 && numFields < 2) {
6069:     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6070:     PetscFunctionReturn(PETSC_SUCCESS);
6071:   }
6072:   /* Get points */
6073:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp));
6074:   /* Get sizes */
6075:   asize = 0;
6076:   for (PetscInt p = 0; p < numPoints * 2; p += 2) {
6077:     PetscInt dof;
6078:     PetscCall(PetscSectionGetDof(section, points[p], &dof));
6079:     asize += dof;
6080:   }
6081:   if (values) {
6082:     const PetscScalar *vArray;
6083:     PetscInt           size;

6085:     if (*values) {
6086:       PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize);
6087:     } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values));
6088:     if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm));
6089:     PetscCall(VecGetArrayRead(v, &vArray));
6090:     /* Get values */
6091:     if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values));
6092:     else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values));
6093:     PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size);
6094:     /* Cleanup array */
6095:     PetscCall(VecRestoreArrayRead(v, &vArray));
6096:   }
6097:   if (csize) *csize = asize;
6098:   /* Cleanup points */
6099:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6100:   PetscFunctionReturn(PETSC_SUCCESS);
6101: }

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

6106:   Not collective

6108:   Input Parameters:
6109: + dm      - The `DM`
6110: . section - The section describing the layout in `v`, or `NULL` to use the default section
6111: . v       - The local vector
6112: - point   - The point in the `DM`

6114:   Input/Output Parameters:
6115: + csize  - The size of the input values array, or `NULL`; on output the number of values in the closure
6116: - values - An array to use for the values, or `NULL` to have it allocated automatically;
6117:            if the user provided `NULL`, it is a borrowed array and should not be freed

6119:   Level: intermediate

6121:   Notes:
6122:   `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the
6123:   calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat`
6124:   assembly function, and a user may already have allocated storage for this operation.

6126:   A typical use could be
6127: .vb
6128:    values = NULL;
6129:    PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6130:    for (cl = 0; cl < clSize; ++cl) {
6131:      <Compute on closure>
6132:    }
6133:    PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values));
6134: .ve
6135:   or
6136: .vb
6137:    PetscMalloc1(clMaxSize, &values);
6138:    for (p = pStart; p < pEnd; ++p) {
6139:      clSize = clMaxSize;
6140:      PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values));
6141:      for (cl = 0; cl < clSize; ++cl) {
6142:        <Compute on closure>
6143:      }
6144:    }
6145:    PetscFree(values);
6146: .ve

6148:   Fortran Notes:
6149:   The `csize` argument is not present in the Fortran binding since it is internal to the array.

6151: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6152: @*/
6153: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6154: {
6155:   PetscFunctionBeginHot;
6156:   PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values));
6157:   PetscFunctionReturn(PETSC_SUCCESS);
6158: }

6160: PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
6161: {
6162:   DMLabel            depthLabel;
6163:   PetscSection       clSection;
6164:   IS                 clPoints;
6165:   PetscScalar       *array;
6166:   const PetscScalar *vArray;
6167:   PetscInt          *points = NULL;
6168:   const PetscInt    *clp, *perm = NULL;
6169:   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;

6171:   PetscFunctionBeginHot;
6173:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6176:   PetscCall(DMPlexGetDepth(dm, &mdepth));
6177:   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
6178:   PetscCall(PetscSectionGetNumFields(section, &numFields));
6179:   if (mdepth == 1 && numFields < 2) {
6180:     PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values));
6181:     PetscFunctionReturn(PETSC_SUCCESS);
6182:   }
6183:   /* Get points */
6184:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6185:   for (clsize = 0, p = 0; p < Np; p++) {
6186:     PetscInt dof;
6187:     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6188:     clsize += dof;
6189:   }
6190:   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm));
6191:   /* Filter points */
6192:   for (p = 0; p < numPoints * 2; p += 2) {
6193:     PetscInt dep;

6195:     PetscCall(DMLabelGetValue(depthLabel, points[p], &dep));
6196:     if (dep != depth) continue;
6197:     points[Np * 2 + 0] = points[p];
6198:     points[Np * 2 + 1] = points[p + 1];
6199:     ++Np;
6200:   }
6201:   /* Get array */
6202:   if (!values || !*values) {
6203:     PetscInt asize = 0, dof;

6205:     for (p = 0; p < Np * 2; p += 2) {
6206:       PetscCall(PetscSectionGetDof(section, points[p], &dof));
6207:       asize += dof;
6208:     }
6209:     if (!values) {
6210:       PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6211:       if (csize) *csize = asize;
6212:       PetscFunctionReturn(PETSC_SUCCESS);
6213:     }
6214:     PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array));
6215:   } else {
6216:     array = *values;
6217:   }
6218:   PetscCall(VecGetArrayRead(v, &vArray));
6219:   /* Get values */
6220:   if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array));
6221:   else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array));
6222:   /* Cleanup points */
6223:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6224:   /* Cleanup array */
6225:   PetscCall(VecRestoreArrayRead(v, &vArray));
6226:   if (!*values) {
6227:     if (csize) *csize = size;
6228:     *values = array;
6229:   } else {
6230:     PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size);
6231:     *csize = size;
6232:   }
6233:   PetscFunctionReturn(PETSC_SUCCESS);
6234: }

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

6239:   Not collective

6241:   Input Parameters:
6242: + dm      - The `DM`
6243: . section - The section describing the layout in `v`, or `NULL` to use the default section
6244: . v       - The local vector
6245: . point   - The point in the `DM`
6246: . csize   - The number of values in the closure, or `NULL`
6247: - values  - The array of values, which is a borrowed array and should not be freed

6249:   Level: intermediate

6251:   Note:
6252:   The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()`

6254:   Fortran Notes:
6255:   The `csize` argument is not present in the Fortran binding since it is internal to the array.

6257: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()`
6258: @*/
6259: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6260: {
6261:   PetscInt size = 0;

6263:   PetscFunctionBegin;
6264:   /* Should work without recalculating size */
6265:   PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values));
6266:   *values = NULL;
6267:   PetscFunctionReturn(PETSC_SUCCESS);
6268: }

6270: static inline void add(PetscScalar *x, PetscScalar y)
6271: {
6272:   *x += y;
6273: }
6274: static inline void insert(PetscScalar *x, PetscScalar y)
6275: {
6276:   *x = y;
6277: }

6279: 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[])
6280: {
6281:   PetscInt        cdof;  /* The number of constraints on this point */
6282:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6283:   PetscScalar    *a;
6284:   PetscInt        off, cind = 0, k;

6286:   PetscFunctionBegin;
6287:   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6288:   PetscCall(PetscSectionGetOffset(section, point, &off));
6289:   a = &array[off];
6290:   if (!cdof || setBC) {
6291:     if (clperm) {
6292:       if (perm) {
6293:         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6294:       } else {
6295:         for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6296:       }
6297:     } else {
6298:       if (perm) {
6299:         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6300:       } else {
6301:         for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6302:       }
6303:     }
6304:   } else {
6305:     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
6306:     if (clperm) {
6307:       if (perm) {
6308:         for (k = 0; k < dof; ++k) {
6309:           if ((cind < cdof) && (k == cdofs[cind])) {
6310:             ++cind;
6311:             continue;
6312:           }
6313:           fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6314:         }
6315:       } else {
6316:         for (k = 0; k < dof; ++k) {
6317:           if ((cind < cdof) && (k == cdofs[cind])) {
6318:             ++cind;
6319:             continue;
6320:           }
6321:           fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6322:         }
6323:       }
6324:     } else {
6325:       if (perm) {
6326:         for (k = 0; k < dof; ++k) {
6327:           if ((cind < cdof) && (k == cdofs[cind])) {
6328:             ++cind;
6329:             continue;
6330:           }
6331:           fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6332:         }
6333:       } else {
6334:         for (k = 0; k < dof; ++k) {
6335:           if ((cind < cdof) && (k == cdofs[cind])) {
6336:             ++cind;
6337:             continue;
6338:           }
6339:           fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6340:         }
6341:       }
6342:     }
6343:   }
6344:   PetscFunctionReturn(PETSC_SUCCESS);
6345: }

6347: 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[])
6348: {
6349:   PetscInt        cdof;  /* The number of constraints on this point */
6350:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6351:   PetscScalar    *a;
6352:   PetscInt        off, cind = 0, k;

6354:   PetscFunctionBegin;
6355:   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
6356:   PetscCall(PetscSectionGetOffset(section, point, &off));
6357:   a = &array[off];
6358:   if (cdof) {
6359:     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
6360:     if (clperm) {
6361:       if (perm) {
6362:         for (k = 0; k < dof; ++k) {
6363:           if ((cind < cdof) && (k == cdofs[cind])) {
6364:             fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.));
6365:             cind++;
6366:           }
6367:         }
6368:       } else {
6369:         for (k = 0; k < dof; ++k) {
6370:           if ((cind < cdof) && (k == cdofs[cind])) {
6371:             fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.));
6372:             cind++;
6373:           }
6374:         }
6375:       }
6376:     } else {
6377:       if (perm) {
6378:         for (k = 0; k < dof; ++k) {
6379:           if ((cind < cdof) && (k == cdofs[cind])) {
6380:             fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.));
6381:             cind++;
6382:           }
6383:         }
6384:       } else {
6385:         for (k = 0; k < dof; ++k) {
6386:           if ((cind < cdof) && (k == cdofs[cind])) {
6387:             fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.));
6388:             cind++;
6389:           }
6390:         }
6391:       }
6392:     }
6393:   }
6394:   PetscFunctionReturn(PETSC_SUCCESS);
6395: }

6397: 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[])
6398: {
6399:   PetscScalar    *a;
6400:   PetscInt        fdof, foff, fcdof, foffset = *offset;
6401:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6402:   PetscInt        cind = 0, b;

6404:   PetscFunctionBegin;
6405:   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6406:   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
6407:   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6408:   a = &array[foff];
6409:   if (!fcdof || setBC) {
6410:     if (clperm) {
6411:       if (perm) {
6412:         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6413:       } else {
6414:         for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6415:       }
6416:     } else {
6417:       if (perm) {
6418:         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6419:       } else {
6420:         for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6421:       }
6422:     }
6423:   } else {
6424:     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6425:     if (clperm) {
6426:       if (perm) {
6427:         for (b = 0; b < fdof; b++) {
6428:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6429:             ++cind;
6430:             continue;
6431:           }
6432:           fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6433:         }
6434:       } else {
6435:         for (b = 0; b < fdof; b++) {
6436:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6437:             ++cind;
6438:             continue;
6439:           }
6440:           fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6441:         }
6442:       }
6443:     } else {
6444:       if (perm) {
6445:         for (b = 0; b < fdof; b++) {
6446:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6447:             ++cind;
6448:             continue;
6449:           }
6450:           fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6451:         }
6452:       } else {
6453:         for (b = 0; b < fdof; b++) {
6454:           if ((cind < fcdof) && (b == fcdofs[cind])) {
6455:             ++cind;
6456:             continue;
6457:           }
6458:           fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6459:         }
6460:       }
6461:     }
6462:   }
6463:   *offset += fdof;
6464:   PetscFunctionReturn(PETSC_SUCCESS);
6465: }

6467: 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[])
6468: {
6469:   PetscScalar    *a;
6470:   PetscInt        fdof, foff, fcdof, foffset = *offset;
6471:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6472:   PetscInt        Nc, cind = 0, ncind = 0, b;
6473:   PetscBool       ncSet, fcSet;

6475:   PetscFunctionBegin;
6476:   PetscCall(PetscSectionGetFieldComponents(section, f, &Nc));
6477:   PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6478:   PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof));
6479:   PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff));
6480:   a = &array[foff];
6481:   if (fcdof) {
6482:     /* We just override fcdof and fcdofs with Ncc and comps */
6483:     PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
6484:     if (clperm) {
6485:       if (perm) {
6486:         if (comps) {
6487:           for (b = 0; b < fdof; b++) {
6488:             ncSet = fcSet = PETSC_FALSE;
6489:             if (b % Nc == comps[ncind]) {
6490:               ncind = (ncind + 1) % Ncc;
6491:               ncSet = PETSC_TRUE;
6492:             }
6493:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6494:               ++cind;
6495:               fcSet = PETSC_TRUE;
6496:             }
6497:             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6498:           }
6499:         } else {
6500:           for (b = 0; b < fdof; b++) {
6501:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6502:               fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.));
6503:               ++cind;
6504:             }
6505:           }
6506:         }
6507:       } else {
6508:         if (comps) {
6509:           for (b = 0; b < fdof; b++) {
6510:             ncSet = fcSet = PETSC_FALSE;
6511:             if (b % Nc == comps[ncind]) {
6512:               ncind = (ncind + 1) % Ncc;
6513:               ncSet = PETSC_TRUE;
6514:             }
6515:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6516:               ++cind;
6517:               fcSet = PETSC_TRUE;
6518:             }
6519:             if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6520:           }
6521:         } else {
6522:           for (b = 0; b < fdof; b++) {
6523:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6524:               fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.));
6525:               ++cind;
6526:             }
6527:           }
6528:         }
6529:       }
6530:     } else {
6531:       if (perm) {
6532:         if (comps) {
6533:           for (b = 0; b < fdof; b++) {
6534:             ncSet = fcSet = PETSC_FALSE;
6535:             if (b % Nc == comps[ncind]) {
6536:               ncind = (ncind + 1) % Ncc;
6537:               ncSet = PETSC_TRUE;
6538:             }
6539:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6540:               ++cind;
6541:               fcSet = PETSC_TRUE;
6542:             }
6543:             if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6544:           }
6545:         } else {
6546:           for (b = 0; b < fdof; b++) {
6547:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6548:               fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.));
6549:               ++cind;
6550:             }
6551:           }
6552:         }
6553:       } else {
6554:         if (comps) {
6555:           for (b = 0; b < fdof; b++) {
6556:             ncSet = fcSet = PETSC_FALSE;
6557:             if (b % Nc == comps[ncind]) {
6558:               ncind = (ncind + 1) % Ncc;
6559:               ncSet = PETSC_TRUE;
6560:             }
6561:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6562:               ++cind;
6563:               fcSet = PETSC_TRUE;
6564:             }
6565:             if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6566:           }
6567:         } else {
6568:           for (b = 0; b < fdof; b++) {
6569:             if ((cind < fcdof) && (b == fcdofs[cind])) {
6570:               fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.));
6571:               ++cind;
6572:             }
6573:           }
6574:         }
6575:       }
6576:     }
6577:   }
6578:   *offset += fdof;
6579:   PetscFunctionReturn(PETSC_SUCCESS);
6580: }

6582: static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6583: {
6584:   PetscScalar    *array;
6585:   const PetscInt *cone, *coneO;
6586:   PetscInt        pStart, pEnd, p, numPoints, off, dof;

6588:   PetscFunctionBeginHot;
6589:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6590:   PetscCall(DMPlexGetConeSize(dm, point, &numPoints));
6591:   PetscCall(DMPlexGetCone(dm, point, &cone));
6592:   PetscCall(DMPlexGetConeOrientation(dm, point, &coneO));
6593:   PetscCall(VecGetArray(v, &array));
6594:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6595:     const PetscInt cp = !p ? point : cone[p - 1];
6596:     const PetscInt o  = !p ? 0 : coneO[p - 1];

6598:     if ((cp < pStart) || (cp >= pEnd)) {
6599:       dof = 0;
6600:       continue;
6601:     }
6602:     PetscCall(PetscSectionGetDof(section, cp, &dof));
6603:     /* ADD_VALUES */
6604:     {
6605:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6606:       PetscScalar    *a;
6607:       PetscInt        cdof, coff, cind = 0, k;

6609:       PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof));
6610:       PetscCall(PetscSectionGetOffset(section, cp, &coff));
6611:       a = &array[coff];
6612:       if (!cdof) {
6613:         if (o >= 0) {
6614:           for (k = 0; k < dof; ++k) a[k] += values[off + k];
6615:         } else {
6616:           for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1];
6617:         }
6618:       } else {
6619:         PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs));
6620:         if (o >= 0) {
6621:           for (k = 0; k < dof; ++k) {
6622:             if ((cind < cdof) && (k == cdofs[cind])) {
6623:               ++cind;
6624:               continue;
6625:             }
6626:             a[k] += values[off + k];
6627:           }
6628:         } else {
6629:           for (k = 0; k < dof; ++k) {
6630:             if ((cind < cdof) && (k == cdofs[cind])) {
6631:               ++cind;
6632:               continue;
6633:             }
6634:             a[k] += values[off + dof - k - 1];
6635:           }
6636:         }
6637:       }
6638:     }
6639:   }
6640:   PetscCall(VecRestoreArray(v, &array));
6641:   PetscFunctionReturn(PETSC_SUCCESS);
6642: }

6644: /*@C
6645:   DMPlexVecSetClosure - Set an array of the values on the closure of `point`

6647:   Not collective

6649:   Input Parameters:
6650: + dm      - The `DM`
6651: . section - The section describing the layout in `v`, or `NULL` to use the default section
6652: . v       - The local vector
6653: . point   - The point in the `DM`
6654: . values  - The array of values
6655: - mode    - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`,
6656:          where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions.

6658:   Level: intermediate

6660: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`
6661: @*/
6662: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6663: {
6664:   PetscSection    clSection;
6665:   IS              clPoints;
6666:   PetscScalar    *array;
6667:   PetscInt       *points = NULL;
6668:   const PetscInt *clp, *clperm = NULL;
6669:   PetscInt        depth, numFields, numPoints, p, clsize;

6671:   PetscFunctionBeginHot;
6673:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6676:   PetscCall(DMPlexGetDepth(dm, &depth));
6677:   PetscCall(PetscSectionGetNumFields(section, &numFields));
6678:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
6679:     PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode));
6680:     PetscFunctionReturn(PETSC_SUCCESS);
6681:   }
6682:   /* Get points */
6683:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6684:   for (clsize = 0, p = 0; p < numPoints; p++) {
6685:     PetscInt dof;
6686:     PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
6687:     clsize += dof;
6688:   }
6689:   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
6690:   /* Get array */
6691:   PetscCall(VecGetArray(v, &array));
6692:   /* Get values */
6693:   if (numFields > 0) {
6694:     PetscInt offset = 0, f;
6695:     for (f = 0; f < numFields; ++f) {
6696:       const PetscInt    **perms = NULL;
6697:       const PetscScalar **flips = NULL;

6699:       PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6700:       switch (mode) {
6701:       case INSERT_VALUES:
6702:         for (p = 0; p < numPoints; p++) {
6703:           const PetscInt     point = points[2 * p];
6704:           const PetscInt    *perm  = perms ? perms[p] : NULL;
6705:           const PetscScalar *flip  = flips ? flips[p] : NULL;
6706:           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array));
6707:         }
6708:         break;
6709:       case INSERT_ALL_VALUES:
6710:         for (p = 0; p < numPoints; p++) {
6711:           const PetscInt     point = points[2 * p];
6712:           const PetscInt    *perm  = perms ? perms[p] : NULL;
6713:           const PetscScalar *flip  = flips ? flips[p] : NULL;
6714:           PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array));
6715:         }
6716:         break;
6717:       case INSERT_BC_VALUES:
6718:         for (p = 0; p < numPoints; p++) {
6719:           const PetscInt     point = points[2 * p];
6720:           const PetscInt    *perm  = perms ? perms[p] : NULL;
6721:           const PetscScalar *flip  = flips ? flips[p] : NULL;
6722:           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array));
6723:         }
6724:         break;
6725:       case ADD_VALUES:
6726:         for (p = 0; p < numPoints; p++) {
6727:           const PetscInt     point = points[2 * p];
6728:           const PetscInt    *perm  = perms ? perms[p] : NULL;
6729:           const PetscScalar *flip  = flips ? flips[p] : NULL;
6730:           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array));
6731:         }
6732:         break;
6733:       case ADD_ALL_VALUES:
6734:         for (p = 0; p < numPoints; p++) {
6735:           const PetscInt     point = points[2 * p];
6736:           const PetscInt    *perm  = perms ? perms[p] : NULL;
6737:           const PetscScalar *flip  = flips ? flips[p] : NULL;
6738:           PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array));
6739:         }
6740:         break;
6741:       case ADD_BC_VALUES:
6742:         for (p = 0; p < numPoints; p++) {
6743:           const PetscInt     point = points[2 * p];
6744:           const PetscInt    *perm  = perms ? perms[p] : NULL;
6745:           const PetscScalar *flip  = flips ? flips[p] : NULL;
6746:           PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array));
6747:         }
6748:         break;
6749:       default:
6750:         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6751:       }
6752:       PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6753:     }
6754:   } else {
6755:     PetscInt            dof, off;
6756:     const PetscInt    **perms = NULL;
6757:     const PetscScalar **flips = NULL;

6759:     PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips));
6760:     switch (mode) {
6761:     case INSERT_VALUES:
6762:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6763:         const PetscInt     point = points[2 * p];
6764:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6765:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6766:         PetscCall(PetscSectionGetDof(section, point, &dof));
6767:         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array));
6768:       }
6769:       break;
6770:     case INSERT_ALL_VALUES:
6771:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6772:         const PetscInt     point = points[2 * p];
6773:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6774:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6775:         PetscCall(PetscSectionGetDof(section, point, &dof));
6776:         PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array));
6777:       }
6778:       break;
6779:     case INSERT_BC_VALUES:
6780:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6781:         const PetscInt     point = points[2 * p];
6782:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6783:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6784:         PetscCall(PetscSectionGetDof(section, point, &dof));
6785:         PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array));
6786:       }
6787:       break;
6788:     case ADD_VALUES:
6789:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6790:         const PetscInt     point = points[2 * p];
6791:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6792:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6793:         PetscCall(PetscSectionGetDof(section, point, &dof));
6794:         PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array));
6795:       }
6796:       break;
6797:     case ADD_ALL_VALUES:
6798:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6799:         const PetscInt     point = points[2 * p];
6800:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6801:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6802:         PetscCall(PetscSectionGetDof(section, point, &dof));
6803:         PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array));
6804:       }
6805:       break;
6806:     case ADD_BC_VALUES:
6807:       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6808:         const PetscInt     point = points[2 * p];
6809:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6810:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6811:         PetscCall(PetscSectionGetDof(section, point, &dof));
6812:         PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array));
6813:       }
6814:       break;
6815:     default:
6816:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6817:     }
6818:     PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips));
6819:   }
6820:   /* Cleanup points */
6821:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6822:   /* Cleanup array */
6823:   PetscCall(VecRestoreArray(v, &array));
6824:   PetscFunctionReturn(PETSC_SUCCESS);
6825: }

6827: /* Check whether the given point is in the label. If not, update the offset to skip this point */
6828: static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains)
6829: {
6830:   PetscFunctionBegin;
6831:   *contains = PETSC_TRUE;
6832:   if (label) {
6833:     PetscInt fdof;

6835:     PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains));
6836:     if (!*contains) {
6837:       PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
6838:       *offset += fdof;
6839:       PetscFunctionReturn(PETSC_SUCCESS);
6840:     }
6841:   }
6842:   PetscFunctionReturn(PETSC_SUCCESS);
6843: }

6845: /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
6846: PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt labelId, const PetscScalar values[], InsertMode mode)
6847: {
6848:   PetscSection    clSection;
6849:   IS              clPoints;
6850:   PetscScalar    *array;
6851:   PetscInt       *points = NULL;
6852:   const PetscInt *clp;
6853:   PetscInt        numFields, numPoints, p;
6854:   PetscInt        offset = 0, f;

6856:   PetscFunctionBeginHot;
6858:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
6861:   PetscCall(PetscSectionGetNumFields(section, &numFields));
6862:   /* Get points */
6863:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp));
6864:   /* Get array */
6865:   PetscCall(VecGetArray(v, &array));
6866:   /* Get values */
6867:   for (f = 0; f < numFields; ++f) {
6868:     const PetscInt    **perms = NULL;
6869:     const PetscScalar **flips = NULL;
6870:     PetscBool           contains;

6872:     if (!fieldActive[f]) {
6873:       for (p = 0; p < numPoints * 2; p += 2) {
6874:         PetscInt fdof;
6875:         PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
6876:         offset += fdof;
6877:       }
6878:       continue;
6879:     }
6880:     PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6881:     switch (mode) {
6882:     case INSERT_VALUES:
6883:       for (p = 0; p < numPoints; p++) {
6884:         const PetscInt     point = points[2 * p];
6885:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6886:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6887:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
6888:         if (!contains) continue;
6889:         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array));
6890:       }
6891:       break;
6892:     case INSERT_ALL_VALUES:
6893:       for (p = 0; p < numPoints; p++) {
6894:         const PetscInt     point = points[2 * p];
6895:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6896:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6897:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
6898:         if (!contains) continue;
6899:         PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array));
6900:       }
6901:       break;
6902:     case INSERT_BC_VALUES:
6903:       for (p = 0; p < numPoints; p++) {
6904:         const PetscInt     point = points[2 * p];
6905:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6906:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6907:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
6908:         if (!contains) continue;
6909:         PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array));
6910:       }
6911:       break;
6912:     case ADD_VALUES:
6913:       for (p = 0; p < numPoints; p++) {
6914:         const PetscInt     point = points[2 * p];
6915:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6916:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6917:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
6918:         if (!contains) continue;
6919:         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array));
6920:       }
6921:       break;
6922:     case ADD_ALL_VALUES:
6923:       for (p = 0; p < numPoints; p++) {
6924:         const PetscInt     point = points[2 * p];
6925:         const PetscInt    *perm  = perms ? perms[p] : NULL;
6926:         const PetscScalar *flip  = flips ? flips[p] : NULL;
6927:         PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains));
6928:         if (!contains) continue;
6929:         PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array));
6930:       }
6931:       break;
6932:     default:
6933:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6934:     }
6935:     PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips));
6936:   }
6937:   /* Cleanup points */
6938:   PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp));
6939:   /* Cleanup array */
6940:   PetscCall(VecRestoreArray(v, &array));
6941:   PetscFunctionReturn(PETSC_SUCCESS);
6942: }

6944: static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6945: {
6946:   PetscMPIInt rank;
6947:   PetscInt    i, j;

6949:   PetscFunctionBegin;
6950:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
6951:   PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point));
6952:   for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i]));
6953:   for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i]));
6954:   numCIndices = numCIndices ? numCIndices : numRIndices;
6955:   if (!values) PetscFunctionReturn(PETSC_SUCCESS);
6956:   for (i = 0; i < numRIndices; i++) {
6957:     PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank));
6958:     for (j = 0; j < numCIndices; j++) {
6959: #if defined(PETSC_USE_COMPLEX)
6960:       PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j])));
6961: #else
6962:       PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j]));
6963: #endif
6964:     }
6965:     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
6966:   }
6967:   PetscFunctionReturn(PETSC_SUCCESS);
6968: }

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

6973:   Input Parameters:
6974: + section - The section for this data layout
6975: . islocal - Is the section (and thus indices being requested) local or global?
6976: . point   - The point contributing dofs with these indices
6977: . off     - The global offset of this point
6978: . loff    - The local offset of each field
6979: . setBC   - The flag determining whether to include indices of boundary values
6980: . perm    - A permutation of the dofs on this point, or NULL
6981: - indperm - A permutation of the entire indices array, or NULL

6983:   Output Parameter:
6984: . indices - Indices for dofs on this point

6986:   Level: developer

6988:   Note: The indices could be local or global, depending on the value of 'off'.
6989: */
6990: PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6991: {
6992:   PetscInt        dof;   /* The number of unknowns on this point */
6993:   PetscInt        cdof;  /* The number of constraints on this point */
6994:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6995:   PetscInt        cind = 0, k;

6997:   PetscFunctionBegin;
6998:   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
6999:   PetscCall(PetscSectionGetDof(section, point, &dof));
7000:   PetscCall(PetscSectionGetConstraintDof(section, point, &cdof));
7001:   if (!cdof || setBC) {
7002:     for (k = 0; k < dof; ++k) {
7003:       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
7004:       const PetscInt ind    = indperm ? indperm[preind] : preind;

7006:       indices[ind] = off + k;
7007:     }
7008:   } else {
7009:     PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs));
7010:     for (k = 0; k < dof; ++k) {
7011:       const PetscInt preind = perm ? *loff + perm[k] : *loff + k;
7012:       const PetscInt ind    = indperm ? indperm[preind] : preind;

7014:       if ((cind < cdof) && (k == cdofs[cind])) {
7015:         /* Insert check for returning constrained indices */
7016:         indices[ind] = -(off + k + 1);
7017:         ++cind;
7018:       } else {
7019:         indices[ind] = off + k - (islocal ? 0 : cind);
7020:       }
7021:     }
7022:   }
7023:   *loff += dof;
7024:   PetscFunctionReturn(PETSC_SUCCESS);
7025: }

7027: /*
7028:  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.

7030:  Input Parameters:
7031: + section - a section (global or local)
7032: - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global
7033: . point - point within section
7034: . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
7035: . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
7036: . setBC - identify constrained (boundary condition) points via involution.
7037: . perms - perms[f][permsoff][:] is a permutation of dofs within each field
7038: . permsoff - offset
7039: - indperm - index permutation

7041:  Output Parameter:
7042: . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
7043: . indices - array to hold indices (as defined by section) of each dof associated with point

7045:  Notes:
7046:  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
7047:  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
7048:  in the local vector.

7050:  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
7051:  significant).  It is invalid to call with a global section and setBC=true.

7053:  Developer Note:
7054:  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
7055:  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
7056:  offset could be obtained from the section instead of passing it explicitly as we do now.

7058:  Example:
7059:  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
7060:  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
7061:  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
7062:  The global vector does not store constrained dofs, so when this function returns global indices, say {110, -112, 111}, the value of -112 is an arbitrary flag that should not be interpreted beyond its sign.

7064:  Level: developer
7065: */
7066: PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7067: {
7068:   PetscInt numFields, foff, f;

7070:   PetscFunctionBegin;
7071:   PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC");
7072:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7073:   for (f = 0, foff = 0; f < numFields; ++f) {
7074:     PetscInt        fdof, cfdof;
7075:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7076:     PetscInt        cind = 0, b;
7077:     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

7079:     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7080:     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7081:     if (!cfdof || setBC) {
7082:       for (b = 0; b < fdof; ++b) {
7083:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7084:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7086:         indices[ind] = off + foff + b;
7087:       }
7088:     } else {
7089:       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7090:       for (b = 0; b < fdof; ++b) {
7091:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7092:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7094:         if ((cind < cfdof) && (b == fcdofs[cind])) {
7095:           indices[ind] = -(off + foff + b + 1);
7096:           ++cind;
7097:         } else {
7098:           indices[ind] = off + foff + b - (islocal ? 0 : cind);
7099:         }
7100:       }
7101:     }
7102:     foff += (setBC || islocal ? fdof : (fdof - cfdof));
7103:     foffs[f] += fdof;
7104:   }
7105:   PetscFunctionReturn(PETSC_SUCCESS);
7106: }

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

7111:  . foffs - The offset into 'indices' for each field, since it is segregated by field

7113:  Notes:
7114:  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
7115:  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
7116: */
7117: static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
7118: {
7119:   PetscInt numFields, foff, f;

7121:   PetscFunctionBegin;
7122:   PetscCall(PetscSectionGetNumFields(section, &numFields));
7123:   for (f = 0; f < numFields; ++f) {
7124:     PetscInt        fdof, cfdof;
7125:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7126:     PetscInt        cind = 0, b;
7127:     const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;

7129:     PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof));
7130:     PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof));
7131:     PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff));
7132:     if (!cfdof) {
7133:       for (b = 0; b < fdof; ++b) {
7134:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7135:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7137:         indices[ind] = foff + b;
7138:       }
7139:     } else {
7140:       PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs));
7141:       for (b = 0; b < fdof; ++b) {
7142:         const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b;
7143:         const PetscInt ind    = indperm ? indperm[preind] : preind;

7145:         if ((cind < cfdof) && (b == fcdofs[cind])) {
7146:           indices[ind] = -(foff + b + 1);
7147:           ++cind;
7148:         } else {
7149:           indices[ind] = foff + b - cind;
7150:         }
7151:       }
7152:     }
7153:     foffs[f] += fdof;
7154:   }
7155:   PetscFunctionReturn(PETSC_SUCCESS);
7156: }

7158: 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)
7159: {
7160:   Mat             cMat;
7161:   PetscSection    aSec, cSec;
7162:   IS              aIS;
7163:   PetscInt        aStart = -1, aEnd = -1;
7164:   const PetscInt *anchors;
7165:   PetscInt        numFields, f, p, q, newP = 0;
7166:   PetscInt        newNumPoints = 0, newNumIndices = 0;
7167:   PetscInt       *newPoints, *indices, *newIndices;
7168:   PetscInt        maxAnchor, maxDof;
7169:   PetscInt        newOffsets[32];
7170:   PetscInt       *pointMatOffsets[32];
7171:   PetscInt       *newPointOffsets[32];
7172:   PetscScalar    *pointMat[32];
7173:   PetscScalar    *newValues      = NULL, *tmpValues;
7174:   PetscBool       anyConstrained = PETSC_FALSE;

7176:   PetscFunctionBegin;
7179:   PetscCall(PetscSectionGetNumFields(section, &numFields));

7181:   PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
7182:   /* if there are point-to-point constraints */
7183:   if (aSec) {
7184:     PetscCall(PetscArrayzero(newOffsets, 32));
7185:     PetscCall(ISGetIndices(aIS, &anchors));
7186:     PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
7187:     /* figure out how many points are going to be in the new element matrix
7188:      * (we allow double counting, because it's all just going to be summed
7189:      * into the global matrix anyway) */
7190:     for (p = 0; p < 2 * numPoints; p += 2) {
7191:       PetscInt b    = points[p];
7192:       PetscInt bDof = 0, bSecDof;

7194:       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7195:       if (!bSecDof) continue;
7196:       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7197:       if (bDof) {
7198:         /* this point is constrained */
7199:         /* it is going to be replaced by its anchors */
7200:         PetscInt bOff, q;

7202:         anyConstrained = PETSC_TRUE;
7203:         newNumPoints += bDof;
7204:         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7205:         for (q = 0; q < bDof; q++) {
7206:           PetscInt a = anchors[bOff + q];
7207:           PetscInt aDof;

7209:           PetscCall(PetscSectionGetDof(section, a, &aDof));
7210:           newNumIndices += aDof;
7211:           for (f = 0; f < numFields; ++f) {
7212:             PetscInt fDof;

7214:             PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof));
7215:             newOffsets[f + 1] += fDof;
7216:           }
7217:         }
7218:       } else {
7219:         /* this point is not constrained */
7220:         newNumPoints++;
7221:         newNumIndices += bSecDof;
7222:         for (f = 0; f < numFields; ++f) {
7223:           PetscInt fDof;

7225:           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7226:           newOffsets[f + 1] += fDof;
7227:         }
7228:       }
7229:     }
7230:   }
7231:   if (!anyConstrained) {
7232:     if (outNumPoints) *outNumPoints = 0;
7233:     if (outNumIndices) *outNumIndices = 0;
7234:     if (outPoints) *outPoints = NULL;
7235:     if (outValues) *outValues = NULL;
7236:     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7237:     PetscFunctionReturn(PETSC_SUCCESS);
7238:   }

7240:   if (outNumPoints) *outNumPoints = newNumPoints;
7241:   if (outNumIndices) *outNumIndices = newNumIndices;

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

7245:   if (!outPoints && !outValues) {
7246:     if (offsets) {
7247:       for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
7248:     }
7249:     if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors));
7250:     PetscFunctionReturn(PETSC_SUCCESS);
7251:   }

7253:   PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices);

7255:   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));

7257:   /* workspaces */
7258:   if (numFields) {
7259:     for (f = 0; f < numFields; f++) {
7260:       PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
7261:       PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7262:     }
7263:   } else {
7264:     PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
7265:     PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0]));
7266:   }

7268:   /* get workspaces for the point-to-point matrices */
7269:   if (numFields) {
7270:     PetscInt totalOffset, totalMatOffset;

7272:     for (p = 0; p < numPoints; p++) {
7273:       PetscInt b    = points[2 * p];
7274:       PetscInt bDof = 0, bSecDof;

7276:       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7277:       if (!bSecDof) {
7278:         for (f = 0; f < numFields; f++) {
7279:           newPointOffsets[f][p + 1] = 0;
7280:           pointMatOffsets[f][p + 1] = 0;
7281:         }
7282:         continue;
7283:       }
7284:       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7285:       if (bDof) {
7286:         for (f = 0; f < numFields; f++) {
7287:           PetscInt fDof, q, bOff, allFDof = 0;

7289:           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7290:           PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7291:           for (q = 0; q < bDof; q++) {
7292:             PetscInt a = anchors[bOff + q];
7293:             PetscInt aFDof;

7295:             PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof));
7296:             allFDof += aFDof;
7297:           }
7298:           newPointOffsets[f][p + 1] = allFDof;
7299:           pointMatOffsets[f][p + 1] = fDof * allFDof;
7300:         }
7301:       } else {
7302:         for (f = 0; f < numFields; f++) {
7303:           PetscInt fDof;

7305:           PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof));
7306:           newPointOffsets[f][p + 1] = fDof;
7307:           pointMatOffsets[f][p + 1] = 0;
7308:         }
7309:       }
7310:     }
7311:     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
7312:       newPointOffsets[f][0] = totalOffset;
7313:       pointMatOffsets[f][0] = totalMatOffset;
7314:       for (p = 0; p < numPoints; p++) {
7315:         newPointOffsets[f][p + 1] += newPointOffsets[f][p];
7316:         pointMatOffsets[f][p + 1] += pointMatOffsets[f][p];
7317:       }
7318:       totalOffset    = newPointOffsets[f][numPoints];
7319:       totalMatOffset = pointMatOffsets[f][numPoints];
7320:       PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
7321:     }
7322:   } else {
7323:     for (p = 0; p < numPoints; p++) {
7324:       PetscInt b    = points[2 * p];
7325:       PetscInt bDof = 0, bSecDof;

7327:       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7328:       if (!bSecDof) {
7329:         newPointOffsets[0][p + 1] = 0;
7330:         pointMatOffsets[0][p + 1] = 0;
7331:         continue;
7332:       }
7333:       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7334:       if (bDof) {
7335:         PetscInt bOff, q, allDof = 0;

7337:         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7338:         for (q = 0; q < bDof; q++) {
7339:           PetscInt a = anchors[bOff + q], aDof;

7341:           PetscCall(PetscSectionGetDof(section, a, &aDof));
7342:           allDof += aDof;
7343:         }
7344:         newPointOffsets[0][p + 1] = allDof;
7345:         pointMatOffsets[0][p + 1] = bSecDof * allDof;
7346:       } else {
7347:         newPointOffsets[0][p + 1] = bSecDof;
7348:         pointMatOffsets[0][p + 1] = 0;
7349:       }
7350:     }
7351:     newPointOffsets[0][0] = 0;
7352:     pointMatOffsets[0][0] = 0;
7353:     for (p = 0; p < numPoints; p++) {
7354:       newPointOffsets[0][p + 1] += newPointOffsets[0][p];
7355:       pointMatOffsets[0][p + 1] += pointMatOffsets[0][p];
7356:     }
7357:     PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
7358:   }

7360:   /* output arrays */
7361:   PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));

7363:   /* get the point-to-point matrices; construct newPoints */
7364:   PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor));
7365:   PetscCall(PetscSectionGetMaxDof(section, &maxDof));
7366:   PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices));
7367:   PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));
7368:   if (numFields) {
7369:     for (p = 0, newP = 0; p < numPoints; p++) {
7370:       PetscInt b    = points[2 * p];
7371:       PetscInt o    = points[2 * p + 1];
7372:       PetscInt bDof = 0, bSecDof;

7374:       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7375:       if (!bSecDof) continue;
7376:       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7377:       if (bDof) {
7378:         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;

7380:         fStart[0] = 0;
7381:         fEnd[0]   = 0;
7382:         for (f = 0; f < numFields; f++) {
7383:           PetscInt fDof;

7385:           PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof));
7386:           fStart[f + 1] = fStart[f] + fDof;
7387:           fEnd[f + 1]   = fStart[f + 1];
7388:         }
7389:         PetscCall(PetscSectionGetOffset(cSec, b, &bOff));
7390:         PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices));

7392:         fAnchorStart[0] = 0;
7393:         fAnchorEnd[0]   = 0;
7394:         for (f = 0; f < numFields; f++) {
7395:           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];

7397:           fAnchorStart[f + 1] = fAnchorStart[f] + fDof;
7398:           fAnchorEnd[f + 1]   = fAnchorStart[f + 1];
7399:         }
7400:         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7401:         for (q = 0; q < bDof; q++) {
7402:           PetscInt a = anchors[bOff + q], aOff;

7404:           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7405:           newPoints[2 * (newP + q)]     = a;
7406:           newPoints[2 * (newP + q) + 1] = 0;
7407:           PetscCall(PetscSectionGetOffset(section, a, &aOff));
7408:           PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices));
7409:         }
7410:         newP += bDof;

7412:         if (outValues) {
7413:           /* get the point-to-point submatrix */
7414:           for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p]));
7415:         }
7416:       } else {
7417:         newPoints[2 * newP]     = b;
7418:         newPoints[2 * newP + 1] = o;
7419:         newP++;
7420:       }
7421:     }
7422:   } else {
7423:     for (p = 0; p < numPoints; p++) {
7424:       PetscInt b    = points[2 * p];
7425:       PetscInt o    = points[2 * p + 1];
7426:       PetscInt bDof = 0, bSecDof;

7428:       PetscCall(PetscSectionGetDof(section, b, &bSecDof));
7429:       if (!bSecDof) continue;
7430:       if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof));
7431:       if (bDof) {
7432:         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;

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

7437:         PetscCall(PetscSectionGetOffset(aSec, b, &bOff));
7438:         for (q = 0; q < bDof; q++) {
7439:           PetscInt a = anchors[bOff + q], aOff;

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

7443:           newPoints[2 * (newP + q)]     = a;
7444:           newPoints[2 * (newP + q) + 1] = 0;
7445:           PetscCall(PetscSectionGetOffset(section, a, &aOff));
7446:           PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices));
7447:         }
7448:         newP += bDof;

7450:         /* get the point-to-point submatrix */
7451:         if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p]));
7452:       } else {
7453:         newPoints[2 * newP]     = b;
7454:         newPoints[2 * newP + 1] = o;
7455:         newP++;
7456:       }
7457:     }
7458:   }

7460:   if (outValues) {
7461:     PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
7462:     PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices));
7463:     /* multiply constraints on the right */
7464:     if (numFields) {
7465:       for (f = 0; f < numFields; f++) {
7466:         PetscInt oldOff = offsets[f];

7468:         for (p = 0; p < numPoints; p++) {
7469:           PetscInt cStart = newPointOffsets[f][p];
7470:           PetscInt b      = points[2 * p];
7471:           PetscInt c, r, k;
7472:           PetscInt dof;

7474:           PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7475:           if (!dof) continue;
7476:           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7477:             PetscInt           nCols = newPointOffsets[f][p + 1] - cStart;
7478:             const PetscScalar *mat   = pointMat[f] + pointMatOffsets[f][p];

7480:             for (r = 0; r < numIndices; r++) {
7481:               for (c = 0; c < nCols; c++) {
7482:                 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7483:               }
7484:             }
7485:           } else {
7486:             /* copy this column as is */
7487:             for (r = 0; r < numIndices; r++) {
7488:               for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7489:             }
7490:           }
7491:           oldOff += dof;
7492:         }
7493:       }
7494:     } else {
7495:       PetscInt oldOff = 0;
7496:       for (p = 0; p < numPoints; p++) {
7497:         PetscInt cStart = newPointOffsets[0][p];
7498:         PetscInt b      = points[2 * p];
7499:         PetscInt c, r, k;
7500:         PetscInt dof;

7502:         PetscCall(PetscSectionGetDof(section, b, &dof));
7503:         if (!dof) continue;
7504:         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7505:           PetscInt           nCols = newPointOffsets[0][p + 1] - cStart;
7506:           const PetscScalar *mat   = pointMat[0] + pointMatOffsets[0][p];

7508:           for (r = 0; r < numIndices; r++) {
7509:             for (c = 0; c < nCols; c++) {
7510:               for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7511:             }
7512:           }
7513:         } else {
7514:           /* copy this column as is */
7515:           for (r = 0; r < numIndices; r++) {
7516:             for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7517:           }
7518:         }
7519:         oldOff += dof;
7520:       }
7521:     }

7523:     if (multiplyLeft) {
7524:       PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues));
7525:       PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices));
7526:       /* multiply constraints transpose on the left */
7527:       if (numFields) {
7528:         for (f = 0; f < numFields; f++) {
7529:           PetscInt oldOff = offsets[f];

7531:           for (p = 0; p < numPoints; p++) {
7532:             PetscInt rStart = newPointOffsets[f][p];
7533:             PetscInt b      = points[2 * p];
7534:             PetscInt c, r, k;
7535:             PetscInt dof;

7537:             PetscCall(PetscSectionGetFieldDof(section, b, f, &dof));
7538:             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7539:               PetscInt                          nRows = newPointOffsets[f][p + 1] - rStart;
7540:               const PetscScalar *PETSC_RESTRICT mat   = pointMat[f] + pointMatOffsets[f][p];

7542:               for (r = 0; r < nRows; r++) {
7543:                 for (c = 0; c < newNumIndices; c++) {
7544:                   for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7545:                 }
7546:               }
7547:             } else {
7548:               /* copy this row as is */
7549:               for (r = 0; r < dof; r++) {
7550:                 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7551:               }
7552:             }
7553:             oldOff += dof;
7554:           }
7555:         }
7556:       } else {
7557:         PetscInt oldOff = 0;

7559:         for (p = 0; p < numPoints; p++) {
7560:           PetscInt rStart = newPointOffsets[0][p];
7561:           PetscInt b      = points[2 * p];
7562:           PetscInt c, r, k;
7563:           PetscInt dof;

7565:           PetscCall(PetscSectionGetDof(section, b, &dof));
7566:           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7567:             PetscInt                          nRows = newPointOffsets[0][p + 1] - rStart;
7568:             const PetscScalar *PETSC_RESTRICT mat   = pointMat[0] + pointMatOffsets[0][p];

7570:             for (r = 0; r < nRows; r++) {
7571:               for (c = 0; c < newNumIndices; c++) {
7572:                 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7573:               }
7574:             }
7575:           } else {
7576:             /* copy this row as is */
7577:             for (r = 0; r < dof; r++) {
7578:               for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7579:             }
7580:           }
7581:           oldOff += dof;
7582:         }
7583:       }

7585:       PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues));
7586:     } else {
7587:       newValues = tmpValues;
7588:     }
7589:   }

7591:   /* clean up */
7592:   PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices));
7593:   PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices));

7595:   if (numFields) {
7596:     for (f = 0; f < numFields; f++) {
7597:       PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f]));
7598:       PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f]));
7599:       PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f]));
7600:     }
7601:   } else {
7602:     PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0]));
7603:     PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0]));
7604:     PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0]));
7605:   }
7606:   PetscCall(ISRestoreIndices(aIS, &anchors));

7608:   /* output */
7609:   if (outPoints) {
7610:     *outPoints = newPoints;
7611:   } else {
7612:     PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints));
7613:   }
7614:   if (outValues) *outValues = newValues;
7615:   for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f];
7616:   PetscFunctionReturn(PETSC_SUCCESS);
7617: }

7619: /*@C
7620:   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.

7622:   Not collective

7624:   Input Parameters:
7625: + dm         - The `DM`
7626: . section    - The `PetscSection` describing the points (a local section)
7627: . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
7628: . point      - The point defining the closure
7629: - useClPerm  - Use the closure point permutation if available

7631:   Output Parameters:
7632: + numIndices - The number of dof indices in the closure of point with the input sections
7633: . indices    - The dof indices
7634: . outOffsets - Array to write the field offsets into, or `NULL`
7635: - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`

7637:   Level: advanced

7639:   Notes:
7640:   Must call `DMPlexRestoreClosureIndices()` to free allocated memory

7642:   If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
7643:   of those indices is not significant.  If `idxSection` is local, the constrained dofs will yield the involution -(idx+1)
7644:   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7645:   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when `idxSection` == section, otherwise global
7646:   indices (with the above semantics) are implied.

7648: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`,
7649:           `PetscSection`, `DMGetGlobalSection()`
7650: @*/
7651: PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7652: {
7653:   /* Closure ordering */
7654:   PetscSection    clSection;
7655:   IS              clPoints;
7656:   const PetscInt *clp;
7657:   PetscInt       *points;
7658:   const PetscInt *clperm = NULL;
7659:   /* Dof permutation and sign flips */
7660:   const PetscInt    **perms[32] = {NULL};
7661:   const PetscScalar **flips[32] = {NULL};
7662:   PetscScalar        *valCopy   = NULL;
7663:   /* Hanging node constraints */
7664:   PetscInt    *pointsC = NULL;
7665:   PetscScalar *valuesC = NULL;
7666:   PetscInt     NclC, NiC;

7668:   PetscInt *idx;
7669:   PetscInt  Nf, Ncl, Ni = 0, offsets[32], p, f;
7670:   PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;

7672:   PetscFunctionBeginHot;
7676:   if (numIndices) PetscAssertPointer(numIndices, 6);
7677:   if (indices) PetscAssertPointer(indices, 7);
7678:   if (outOffsets) PetscAssertPointer(outOffsets, 8);
7679:   if (values) PetscAssertPointer(values, 9);
7680:   PetscCall(PetscSectionGetNumFields(section, &Nf));
7681:   PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf);
7682:   PetscCall(PetscArrayzero(offsets, 32));
7683:   /* 1) Get points in closure */
7684:   PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp));
7685:   if (useClPerm) {
7686:     PetscInt depth, clsize;
7687:     PetscCall(DMPlexGetPointDepth(dm, point, &depth));
7688:     for (clsize = 0, p = 0; p < Ncl; p++) {
7689:       PetscInt dof;
7690:       PetscCall(PetscSectionGetDof(section, points[2 * p], &dof));
7691:       clsize += dof;
7692:     }
7693:     PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm));
7694:   }
7695:   /* 2) Get number of indices on these points and field offsets from section */
7696:   for (p = 0; p < Ncl * 2; p += 2) {
7697:     PetscInt dof, fdof;

7699:     PetscCall(PetscSectionGetDof(section, points[p], &dof));
7700:     for (f = 0; f < Nf; ++f) {
7701:       PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof));
7702:       offsets[f + 1] += fdof;
7703:     }
7704:     Ni += dof;
7705:   }
7706:   for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f];
7707:   PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni);
7708:   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
7709:   for (f = 0; f < PetscMax(1, Nf); ++f) {
7710:     if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7711:     else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]));
7712:     /* may need to apply sign changes to the element matrix */
7713:     if (values && flips[f]) {
7714:       PetscInt foffset = offsets[f];

7716:       for (p = 0; p < Ncl; ++p) {
7717:         PetscInt           pnt  = points[2 * p], fdof;
7718:         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;

7720:         if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof));
7721:         else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof));
7722:         if (flip) {
7723:           PetscInt i, j, k;

7725:           if (!valCopy) {
7726:             PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
7727:             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
7728:             *values = valCopy;
7729:           }
7730:           for (i = 0; i < fdof; ++i) {
7731:             PetscScalar fval = flip[i];

7733:             for (k = 0; k < Ni; ++k) {
7734:               valCopy[Ni * (foffset + i) + k] *= fval;
7735:               valCopy[Ni * k + (foffset + i)] *= fval;
7736:             }
7737:           }
7738:         }
7739:         foffset += fdof;
7740:       }
7741:     }
7742:   }
7743:   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
7744:   PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE));
7745:   if (NclC) {
7746:     if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy));
7747:     for (f = 0; f < PetscMax(1, Nf); ++f) {
7748:       if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7749:       else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
7750:     }
7751:     for (f = 0; f < PetscMax(1, Nf); ++f) {
7752:       if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]));
7753:       else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]));
7754:     }
7755:     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7756:     Ncl    = NclC;
7757:     Ni     = NiC;
7758:     points = pointsC;
7759:     if (values) *values = valuesC;
7760:   }
7761:   /* 5) Calculate indices */
7762:   PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx));
7763:   if (Nf) {
7764:     PetscInt  idxOff;
7765:     PetscBool useFieldOffsets;

7767:     if (outOffsets) {
7768:       for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];
7769:     }
7770:     PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets));
7771:     if (useFieldOffsets) {
7772:       for (p = 0; p < Ncl; ++p) {
7773:         const PetscInt pnt = points[p * 2];

7775:         PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx));
7776:       }
7777:     } else {
7778:       for (p = 0; p < Ncl; ++p) {
7779:         const PetscInt pnt = points[p * 2];

7781:         PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
7782:         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7783:          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
7784:          * global section. */
7785:         PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx));
7786:       }
7787:     }
7788:   } else {
7789:     PetscInt off = 0, idxOff;

7791:     for (p = 0; p < Ncl; ++p) {
7792:       const PetscInt  pnt  = points[p * 2];
7793:       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;

7795:       PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff));
7796:       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7797:        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
7798:       PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx));
7799:     }
7800:   }
7801:   /* 6) Cleanup */
7802:   for (f = 0; f < PetscMax(1, Nf); ++f) {
7803:     if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]));
7804:     else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]));
7805:   }
7806:   if (NclC) {
7807:     PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC));
7808:   } else {
7809:     PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp));
7810:   }

7812:   if (numIndices) *numIndices = Ni;
7813:   if (indices) *indices = idx;
7814:   PetscFunctionReturn(PETSC_SUCCESS);
7815: }

7817: /*@C
7818:   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.

7820:   Not collective

7822:   Input Parameters:
7823: + dm         - The `DM`
7824: . section    - The `PetscSection` describing the points (a local section)
7825: . idxSection - The `PetscSection` from which to obtain indices (may be local or global)
7826: . point      - The point defining the closure
7827: - useClPerm  - Use the closure point permutation if available

7829:   Output Parameters:
7830: + numIndices - The number of dof indices in the closure of point with the input sections
7831: . indices    - The dof indices
7832: . outOffsets - Array to write the field offsets into, or `NULL`
7833: - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL`

7835:   Level: advanced

7837:   Notes:
7838:   If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values).

7840:   If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices.  The value
7841:   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7842:   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7843:   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7844:   indices (with the above semantics) are implied.

7846: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
7847: @*/
7848: PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7849: {
7850:   PetscFunctionBegin;
7852:   PetscAssertPointer(indices, 7);
7853:   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices));
7854:   PetscFunctionReturn(PETSC_SUCCESS);
7855: }

7857: PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7858: {
7859:   DM_Plex           *mesh = (DM_Plex *)dm->data;
7860:   PetscInt          *indices;
7861:   PetscInt           numIndices;
7862:   const PetscScalar *valuesOrig = values;
7863:   PetscErrorCode     ierr;

7865:   PetscFunctionBegin;
7867:   if (!section) PetscCall(DMGetLocalSection(dm, &section));
7869:   if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection));

7873:   PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values));

7875:   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values));
7876:   /* TODO: fix this code to not use error codes as handle-able exceptions! */
7877:   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7878:   if (ierr) {
7879:     PetscMPIInt rank;

7881:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
7882:     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
7883:     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values));
7884:     PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
7885:     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
7886:     SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values");
7887:   }
7888:   if (mesh->printFEM > 1) {
7889:     PetscInt i;
7890:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Indices:"));
7891:     for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i]));
7892:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
7893:   }

7895:   PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values));
7896:   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values));
7897:   PetscFunctionReturn(PETSC_SUCCESS);
7898: }

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

7903:   Not collective

7905:   Input Parameters:
7906: + dm            - The `DM`
7907: . section       - The section describing the layout in `v`, or `NULL` to use the default section
7908: . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section
7909: . A             - The matrix
7910: . point         - The point in the `DM`
7911: . values        - The array of values
7912: - mode          - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions

7914:   Level: intermediate

7916: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
7917: @*/
7918: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7919: {
7920:   PetscFunctionBegin;
7921:   PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode));
7922:   PetscFunctionReturn(PETSC_SUCCESS);
7923: }

7925: /*@C
7926:   DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section

7928:   Not collective

7930:   Input Parameters:
7931: + dmRow            - The `DM` for the row fields
7932: . sectionRow       - The section describing the layout, or `NULL` to use the default section in `dmRow`
7933: . useRowPerm       - The flag to use the closure permutation of the `dmRow` if available
7934: . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow`
7935: . dmCol            - The `DM` for the column fields
7936: . sectionCol       - The section describing the layout, or `NULL` to use the default section in `dmCol`
7937: . useColPerm       - The flag to use the closure permutation of the `dmCol` if available
7938: . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol`
7939: . A                - The matrix
7940: . point            - The point in the `DM`
7941: . values           - The array of values
7942: - mode             - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions

7944:   Level: intermediate

7946: .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`
7947: @*/
7948: PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, PetscBool useRowPerm, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, PetscBool useColPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7949: {
7950:   DM_Plex           *mesh = (DM_Plex *)dmRow->data;
7951:   PetscInt          *indicesRow, *indicesCol;
7952:   PetscInt           numIndicesRow, numIndicesCol;
7953:   const PetscScalar *valuesOrig = values;
7954:   PetscErrorCode     ierr;

7956:   PetscFunctionBegin;
7958:   if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, &sectionRow));
7960:   if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow));
7963:   if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, &sectionCol));
7965:   if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol));

7969:   PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
7970:   PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));

7972:   if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
7973:   /* TODO: fix this code to not use error codes as handle-able exceptions! */
7974:   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
7975:   if (ierr) {
7976:     PetscMPIInt rank;

7978:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
7979:     PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank));
7980:     PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values));
7981:     PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
7982:     PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values));
7983:     if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7984:   }

7986:   PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values));
7987:   PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values));
7988:   if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values));
7989:   PetscFunctionReturn(PETSC_SUCCESS);
7990: }

7992: PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7993: {
7994:   DM_Plex        *mesh    = (DM_Plex *)dmf->data;
7995:   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
7996:   PetscInt       *cpoints = NULL;
7997:   PetscInt       *findices, *cindices;
7998:   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7999:   PetscInt        foffsets[32], coffsets[32];
8000:   DMPolytopeType  ct;
8001:   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
8002:   PetscErrorCode  ierr;

8004:   PetscFunctionBegin;
8007:   if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection));
8009:   if (!csection) PetscCall(DMGetLocalSection(dmc, &csection));
8011:   if (!globalFSection)